mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge remote-tracking branch 'origin/main' into rb/rack-env-query-string
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
classMethodCalls
|
||||
| test1.rb:58:1:58:8 | Use getMember("M1").getMember("C1").getMethod("m").getReturn() |
|
||||
| test1.rb:59:1:59:8 | Use getMember("M2").getMember("C3").getMethod("m").getReturn() |
|
||||
| test1.rb:58:1:58:8 | ForwardNode(call to m) |
|
||||
| test1.rb:59:1:59:8 | ForwardNode(call to m) |
|
||||
instanceMethodCalls
|
||||
| test1.rb:61:1:61:12 | Use getMember("M1").getMember("C1").getMethod("new").getReturn().getMethod("m").getReturn() |
|
||||
| test1.rb:62:1:62:12 | Use getMember("M2").getMember("C3").getMethod("new").getReturn().getMethod("m").getReturn() |
|
||||
| test1.rb:61:1:61:12 | ForwardNode(call to m) |
|
||||
| test1.rb:62:1:62:12 | ForwardNode(call to m) |
|
||||
flowThroughArray
|
||||
| test1.rb:73:1:73:10 | call to m |
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import ruby
|
||||
import codeql.ruby.ast.internal.TreeSitter
|
||||
import codeql.ruby.dataflow.internal.AccessPathSyntax
|
||||
import codeql.ruby.frameworks.data.internal.ApiGraphModels
|
||||
import codeql.ruby.ApiGraphs
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class AccessPathFromExpectation extends AccessPath::Range {
|
||||
AccessPathFromExpectation() { hasExpectationWithValue(_, this) }
|
||||
}
|
||||
|
||||
API::Node evaluatePath(AccessPath path, int n) {
|
||||
path instanceof AccessPathFromExpectation and
|
||||
n = 1 and
|
||||
exists(AccessPathToken token | token = path.getToken(0) |
|
||||
token.getName() = "Member" and
|
||||
result = API::getTopLevelMember(token.getAnArgument())
|
||||
or
|
||||
token.getName() = "Method" and
|
||||
result = API::getTopLevelCall(token.getAnArgument())
|
||||
or
|
||||
token.getName() = "EntryPoint" and
|
||||
result = token.getAnArgument().(API::EntryPoint).getANode()
|
||||
)
|
||||
or
|
||||
result = getSuccessorFromNode(evaluatePath(path, n - 1), path.getToken(n - 1))
|
||||
or
|
||||
result = getSuccessorFromInvoke(evaluatePath(path, n - 1), path.getToken(n - 1))
|
||||
or
|
||||
// TODO this is a workaround, support parsing of Method['[]'] instead
|
||||
path.getToken(n - 1).getName() = "MethodBracket" and
|
||||
result = evaluatePath(path, n - 1).getMethod("[]")
|
||||
}
|
||||
|
||||
API::Node evaluatePath(AccessPath path) { result = evaluatePath(path, path.getNumToken()) }
|
||||
|
||||
module ApiUseTest implements TestSig {
|
||||
string getARelevantTag() { result = ["source", "sink", "call", "reachableFromSource"] }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
// All results are considered optional
|
||||
none()
|
||||
}
|
||||
|
||||
predicate hasOptionalResult(Location location, string element, string tag, string value) {
|
||||
exists(API::Node apiNode, DataFlow::Node dataflowNode |
|
||||
apiNode = evaluatePath(value) and
|
||||
(
|
||||
tag = "source" and dataflowNode = apiNode.asSource()
|
||||
or
|
||||
tag = "reachableFromSource" and dataflowNode = apiNode.getAValueReachableFromSource()
|
||||
or
|
||||
tag = "sink" and dataflowNode = apiNode.asSink()
|
||||
or
|
||||
tag = "call" and dataflowNode = apiNode.asCall()
|
||||
) and
|
||||
location = dataflowNode.getLocation() and
|
||||
element = dataflowNode.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<ApiUseTest>
|
||||
|
||||
class CustomEntryPointCall extends API::EntryPoint {
|
||||
CustomEntryPointCall() { this = "CustomEntryPointCall" }
|
||||
|
||||
override DataFlow::CallNode getACall() { result.getMethodName() = "customEntryPointCall" }
|
||||
}
|
||||
|
||||
class CustomEntryPointUse extends API::EntryPoint {
|
||||
CustomEntryPointUse() { this = "CustomEntryPointUse" }
|
||||
|
||||
override DataFlow::LocalSourceNode getASource() {
|
||||
result.(DataFlow::CallNode).getMethodName() = "customEntryPointUse"
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,39 @@
|
||||
Something.foo.withCallback do |a, b| #$ use=getMember("Something").getMethod("foo").getReturn()
|
||||
a.something #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getBlock().getParameter(0).getMethod("something").getReturn()
|
||||
b.somethingElse #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getBlock().getParameter(1).getMethod("somethingElse").getReturn()
|
||||
end #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getReturn()
|
||||
Something.foo.withCallback do |a, b| #$ source=Member[Something].Method[foo].ReturnValue
|
||||
a.something #$ source=Member[Something].Method[foo].ReturnValue.Method[withCallback].Argument[block].Argument[0].Method[something].ReturnValue
|
||||
b.somethingElse #$ source=Member[Something].Method[foo].ReturnValue.Method[withCallback].Argument[block].Argument[1].Method[somethingElse].ReturnValue
|
||||
end #$ source=Member[Something].Method[foo].ReturnValue.Method[withCallback].ReturnValue
|
||||
|
||||
Something.withNamedArg do |a:, b: nil| #$ use=getMember("Something")
|
||||
a.something #$ use=getMember("Something").getMethod("withNamedArg").getBlock().getKeywordParameter("a").getMethod("something").getReturn()
|
||||
b.somethingElse #$ use=getMember("Something").getMethod("withNamedArg").getBlock().getKeywordParameter("b").getMethod("somethingElse").getReturn()
|
||||
end #$ use=getMember("Something").getMethod("withNamedArg").getReturn()
|
||||
Something.withNamedArg do |a:, b: nil| #$ source=Member[Something]
|
||||
a.something #$ source=Member[Something].Method[withNamedArg].Argument[block].Parameter[a:].Method[something].ReturnValue
|
||||
b.somethingElse #$ source=Member[Something].Method[withNamedArg].Argument[block].Parameter[b:].Method[somethingElse].ReturnValue
|
||||
end #$ source=Member[Something].Method[withNamedArg].ReturnValue
|
||||
|
||||
Something.withLambda ->(a, b) { #$ use=getMember("Something")
|
||||
a.something #$ use=getMember("Something").getMethod("withLambda").getParameter(0).getParameter(0).getMethod("something").getReturn()
|
||||
b.something #$ use=getMember("Something").getMethod("withLambda").getParameter(0).getParameter(1).getMethod("something").getReturn()
|
||||
} #$ use=getMember("Something").getMethod("withLambda").getReturn()
|
||||
Something.withLambda ->(a, b) { #$ source=Member[Something]
|
||||
a.something #$ source=Member[Something].Method[withLambda].Argument[0].Parameter[0].Method[something].ReturnValue
|
||||
b.something #$ source=Member[Something].Method[withLambda].Argument[0].Parameter[1].Method[something].ReturnValue
|
||||
} #$ source=Member[Something].Method[withLambda].ReturnValue
|
||||
|
||||
Something.namedCallback( #$ use=getMember("Something")
|
||||
Something.namedCallback( #$ source=Member[Something]
|
||||
onEvent: ->(a, b) {
|
||||
a.something #$ use=getMember("Something").getMethod("namedCallback").getKeywordParameter("onEvent").getParameter(0).getMethod("something").getReturn()
|
||||
b.something #$ use=getMember("Something").getMethod("namedCallback").getKeywordParameter("onEvent").getParameter(1).getMethod("something").getReturn()
|
||||
a.something #$ source=Member[Something].Method[namedCallback].Argument[onEvent:].Parameter[0].Method[something].ReturnValue
|
||||
b.something #$ source=Member[Something].Method[namedCallback].Argument[onEvent:].Parameter[1].Method[something].ReturnValue
|
||||
}
|
||||
) #$ use=getMember("Something").getMethod("namedCallback").getReturn()
|
||||
) #$ source=Member[Something].Method[namedCallback].ReturnValue
|
||||
|
||||
Something.nestedCall1 do |a| #$ use=getMember("Something")
|
||||
a.nestedCall2 do |b:| #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0)
|
||||
b.something #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0).getMethod("nestedCall2").getBlock().getKeywordParameter("b").getMethod("something").getReturn()
|
||||
end #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0).getMethod("nestedCall2").getReturn()
|
||||
end #$ use=getMember("Something").getMethod("nestedCall1").getReturn()
|
||||
Something.nestedCall1 do |a| #$ source=Member[Something]
|
||||
a.nestedCall2 do |b:| #$ reachableFromSource=Member[Something].Method[nestedCall1].Argument[block].Parameter[0]
|
||||
b.something #$ source=Member[Something].Method[nestedCall1].Argument[block].Parameter[0].Method[nestedCall2].Argument[block].Parameter[b:].Method[something].ReturnValue
|
||||
end #$ source=Member[Something].Method[nestedCall1].Argument[block].Parameter[0].Method[nestedCall2].ReturnValue
|
||||
end #$ source=Member[Something].Method[nestedCall1].ReturnValue
|
||||
|
||||
def getCallback()
|
||||
->(x) {
|
||||
x.something #$ use=getMember("Something").getMethod("indirectCallback").getParameter(0).getParameter(0).getMethod("something").getReturn()
|
||||
x.something #$ source=Member[Something].Method[indirectCallback].Argument[0].Parameter[0].Method[something].ReturnValue
|
||||
}
|
||||
end
|
||||
Something.indirectCallback(getCallback()) #$ use=getMember("Something").getMethod("indirectCallback").getReturn()
|
||||
Something.indirectCallback(getCallback()) #$ source=Member[Something].Method[indirectCallback].ReturnValue
|
||||
|
||||
Something.withMixed do |a, *args, b| #$ use=getMember("Something")
|
||||
a.something #$ use=getMember("Something").getMethod("withMixed").getBlock().getParameter(0).getMethod("something").getReturn()
|
||||
Something.withMixed do |a, *args, b| #$ source=Member[Something]
|
||||
a.something #$ source=Member[Something].Method[withMixed].Argument[block].Parameter[0].Method[something].ReturnValue
|
||||
# b.something # not currently handled correctly
|
||||
end #$ use=getMember("Something").getMethod("withMixed").getReturn()
|
||||
end #$ source=Member[Something].Method[withMixed].ReturnValue
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
def chained_access1
|
||||
Something.foo [[[
|
||||
'sink' # $ sink=Member[Something].Method[foo].Argument[0].Element[0].Element[0].Element[0]
|
||||
]]]
|
||||
end
|
||||
|
||||
def chained_access2
|
||||
array = []
|
||||
array[0] = [[
|
||||
'sink' # $ sink=Member[Something].Method[foo].Argument[0].Element[0].Element[0].Element[0]
|
||||
]]
|
||||
Something.foo array
|
||||
end
|
||||
|
||||
def chained_access3
|
||||
array = [[]]
|
||||
array[0][0] = [
|
||||
'sink' # $ sink=Member[Something].Method[foo].Argument[0].Element[0].Element[0].Element[0]
|
||||
]
|
||||
Something.foo array
|
||||
end
|
||||
|
||||
def chained_access4
|
||||
Something.foo {
|
||||
:one => {
|
||||
:two => {
|
||||
:three => 'sink' # $ sink=Member[Something].Method[foo].Argument[0].Element[:one].Element[:two].Element[:three]
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
Foo.bar proc { |x|
|
||||
x # $ reachableFromSource=Member[Foo].Method[bar].Argument[0].Parameter[0]
|
||||
}
|
||||
|
||||
Foo.bar lambda { |x|
|
||||
x # $ reachableFromSource=Member[Foo].Method[bar].Argument[0].Parameter[0]
|
||||
}
|
||||
|
||||
Foo.bar Proc.new { |x|
|
||||
x # $ reachableFromSource=Member[Foo].Method[bar].Argument[0].Parameter[0]
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
class BaseClass
|
||||
def inheritedInstanceMethod
|
||||
yield "taint" # $ sink=Member[Something].Method[foo].Argument[block].ReturnValue.Method[inheritedInstanceMethod].Parameter[block].Argument[0]
|
||||
end
|
||||
|
||||
def self.inheritedSingletonMethod
|
||||
yield "taint" # $ sink=Member[Something].Method[bar].Argument[block].ReturnValue.Method[inheritedSingletonMethod].Parameter[block].Argument[0]
|
||||
end
|
||||
end
|
||||
|
||||
class ClassWithCallbacks < BaseClass
|
||||
def instanceMethod
|
||||
yield "taint" # $ sink=Member[Something].Method[foo].Argument[block].ReturnValue.Method[instanceMethod].Parameter[block].Argument[0]
|
||||
end
|
||||
|
||||
def self.singletonMethod
|
||||
yield "bar" # $ sink=Member[Something].Method[bar].Argument[block].ReturnValue.Method[singletonMethod].Parameter[block].Argument[0]
|
||||
end
|
||||
|
||||
def escapeSelf
|
||||
Something.baz { self }
|
||||
end
|
||||
|
||||
def self.escapeSingletonSelf
|
||||
Something.baz { self }
|
||||
end
|
||||
|
||||
def self.foo x
|
||||
x # $ reachableFromSource=Member[BaseClass].Method[foo].Parameter[0]
|
||||
x # $ reachableFromSource=Member[ClassWithCallbacks].Method[foo].Parameter[0]
|
||||
x # $ reachableFromSource=Member[Subclass].Method[foo].Parameter[0]
|
||||
end
|
||||
|
||||
def bar x
|
||||
x # $ reachableFromSource=Member[BaseClass].Instance.Method[bar].Parameter[0]
|
||||
x # $ reachableFromSource=Member[ClassWithCallbacks].Instance.Method[bar].Parameter[0]
|
||||
x # $ reachableFromSource=Member[Subclass].Instance.Method[bar].Parameter[0]
|
||||
end
|
||||
end
|
||||
|
||||
class Subclass < ClassWithCallbacks
|
||||
def instanceMethodInSubclass
|
||||
yield "bar" # $ sink=Member[Something].Method[baz].Argument[block].ReturnValue.Method[instanceMethodInSubclass].Parameter[block].Argument[0]
|
||||
end
|
||||
|
||||
def self.singletonMethodInSubclass
|
||||
yield "bar" # $ sink=Member[Something].Method[baz].Argument[block].ReturnValue.Method[singletonMethodInSubclass].Parameter[block].Argument[0]
|
||||
end
|
||||
end
|
||||
|
||||
Something.foo { ClassWithCallbacks.new }
|
||||
Something.bar { ClassWithCallbacks }
|
||||
|
||||
class ClassWithCallMethod
|
||||
def call x
|
||||
x # $ reachableFromSource=Method[topLevelMethod].Argument[0].Parameter[0]
|
||||
"bar" # $ sink=Method[topLevelMethod].Argument[0].ReturnValue
|
||||
end
|
||||
end
|
||||
|
||||
topLevelMethod ClassWithCallMethod.new
|
||||
|
||||
blah = topLevelMethod
|
||||
blah # $ reachableFromSource=Method[topLevelMethod].ReturnValue
|
||||
@@ -0,0 +1,10 @@
|
||||
module SelfDotClass
|
||||
module Mixin
|
||||
def foo
|
||||
self.class.bar # $ call=Member[Foo].Method[bar]
|
||||
end
|
||||
end
|
||||
class Subclass < Foo
|
||||
include Mixin
|
||||
end
|
||||
end
|
||||
@@ -1,34 +1,34 @@
|
||||
MyModule #$ use=getMember("MyModule")
|
||||
print MyModule.foo #$ use=getMember("MyModule").getMethod("foo").getReturn()
|
||||
Kernel.print(e) #$ use=getMember("Kernel").getMethod("print").getReturn() def=getMember("Kernel").getMethod("print").getParameter(0)
|
||||
Object::Kernel #$ use=getMember("Kernel")
|
||||
Object::Kernel.print(e) #$ use=getMember("Kernel").getMethod("print").getReturn()
|
||||
MyModule #$ source=Member[MyModule]
|
||||
print MyModule.foo #$ source=Member[MyModule].Method[foo].ReturnValue
|
||||
Kernel.print(e) #$ source=Member[Kernel].Method[print].ReturnValue sink=Member[Kernel].Method[print].Argument[0]
|
||||
Object::Kernel #$ source=Member[Kernel]
|
||||
Object::Kernel.print(e) #$ source=Member[Kernel].Method[print].ReturnValue
|
||||
begin
|
||||
print MyModule.bar #$ use=getMember("MyModule").getMethod("bar").getReturn()
|
||||
raise AttributeError #$ use=getMember("AttributeError")
|
||||
rescue AttributeError => e #$ use=getMember("AttributeError")
|
||||
Kernel.print(e) #$ use=getMember("Kernel").getMethod("print").getReturn()
|
||||
print MyModule.bar #$ source=Member[MyModule].Method[bar].ReturnValue
|
||||
raise AttributeError #$ source=Member[AttributeError]
|
||||
rescue AttributeError => e #$ source=Member[AttributeError]
|
||||
Kernel.print(e) #$ source=Member[Kernel].Method[print].ReturnValue
|
||||
end
|
||||
Unknown.new.run #$ use=getMember("Unknown").getMethod("new").getReturn().getMethod("run").getReturn()
|
||||
Foo::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz")
|
||||
Unknown.new.run #$ source=Member[Unknown].Method[new].ReturnValue.Method[run].ReturnValue
|
||||
Foo::Bar::Baz #$ source=Member[Foo].Member[Bar].Member[Baz]
|
||||
|
||||
Const = [1, 2, 3] #$ use=getMember("Array").getMethod("[]").getReturn()
|
||||
Const.each do |c| #$ use=getMember("Const")
|
||||
puts c #$ use=getMember("Const").getMethod("each").getBlock().getParameter(0) use=getMember("Const").getContent(element)
|
||||
end #$ use=getMember("Const").getMethod("each").getReturn() def=getMember("Const").getMethod("each").getBlock()
|
||||
Const = [1, 2, 3] #$ source=Member[Array].MethodBracket.ReturnValue
|
||||
Const.each do |c| #$ source=Member[Const]
|
||||
puts c #$ reachableFromSource=Member[Const].Method[each].Argument[block].Parameter[0] reachableFromSource=Member[Const].Element[any]
|
||||
end #$ source=Member[Const].Method[each].ReturnValue sink=Member[Const].Method[each].Argument[block]
|
||||
|
||||
foo = Foo #$ use=getMember("Foo")
|
||||
foo::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz")
|
||||
foo = Foo #$ source=Member[Foo]
|
||||
foo::Bar::Baz #$ source=Member[Foo].Member[Bar].Member[Baz]
|
||||
|
||||
FooAlias = Foo #$ use=getMember("Foo")
|
||||
FooAlias::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz")
|
||||
FooAlias = Foo #$ source=Member[Foo]
|
||||
FooAlias::Bar::Baz #$ source=Member[Foo].Member[Bar].Member[Baz] source=Member[FooAlias].Member[Bar].Member[Baz]
|
||||
|
||||
module Outer
|
||||
module Inner
|
||||
end
|
||||
end
|
||||
|
||||
Outer::Inner.foo #$ use=getMember("Outer").getMember("Inner").getMethod("foo").getReturn()
|
||||
Outer::Inner.foo #$ source=Member[Outer].Member[Inner].Method[foo].ReturnValue
|
||||
|
||||
module M1
|
||||
class C1
|
||||
@@ -40,36 +40,36 @@ module M1
|
||||
end
|
||||
end
|
||||
|
||||
class C2 < M1::C1 #$ use=getMember("M1").getMember("C1")
|
||||
class C2 < M1::C1 #$ source=Member[M1].Member[C1]
|
||||
end
|
||||
|
||||
module M2
|
||||
class C3 < M1::C1 #$ use=getMember("M1").getMember("C1")
|
||||
class C3 < M1::C1 #$ source=Member[M1].Member[C1]
|
||||
end
|
||||
|
||||
class C4 < C2 #$ use=getMember("C2")
|
||||
class C4 < C2 #$ source=Member[C2]
|
||||
end
|
||||
end
|
||||
|
||||
C2 #$ use=getMember("C2") use=getMember("M1").getMember("C1").getASubclass()
|
||||
M2::C3 #$ use=getMember("M2").getMember("C3") use=getMember("M1").getMember("C1").getASubclass()
|
||||
M2::C4 #$ use=getMember("M2").getMember("C4") use=getMember("C2").getASubclass() use=getMember("M1").getMember("C1").getASubclass().getASubclass()
|
||||
C2 #$ source=Member[C2] reachableFromSource=Member[M1].Member[C1]
|
||||
M2::C3 #$ source=Member[M2].Member[C3] reachableFromSource=Member[M1].Member[C1]
|
||||
M2::C4 #$ source=Member[M2].Member[C4] reachableFromSource=Member[C2] reachableFromSource=Member[M1].Member[C1]
|
||||
|
||||
M1::C1.m #$ use=getMember("M1").getMember("C1").getMethod("m").getReturn()
|
||||
M2::C3.m #$ use=getMember("M2").getMember("C3").getMethod("m").getReturn() use=getMember("M1").getMember("C1").getASubclass().getMethod("m").getReturn()
|
||||
M1::C1.m #$ source=Member[M1].Member[C1].Method[m].ReturnValue
|
||||
M2::C3.m #$ source=Member[M2].Member[C3].Method[m].ReturnValue source=Member[M1].Member[C1].Method[m].ReturnValue
|
||||
|
||||
M1::C1.new.m #$ use=getMember("M1").getMember("C1").getMethod("new").getReturn().getMethod("m").getReturn()
|
||||
M2::C3.new.m #$ use=getMember("M2").getMember("C3").getMethod("new").getReturn().getMethod("m").getReturn()
|
||||
M1::C1.new.m #$ source=Member[M1].Member[C1].Method[new].ReturnValue.Method[m].ReturnValue
|
||||
M2::C3.new.m #$ source=Member[M2].Member[C3].Method[new].ReturnValue.Method[m].ReturnValue
|
||||
|
||||
Foo.foo(a,b:c) #$ use=getMember("Foo").getMethod("foo").getReturn() def=getMember("Foo").getMethod("foo").getParameter(0) def=getMember("Foo").getMethod("foo").getKeywordParameter("b")
|
||||
Foo.foo(a,b:c) #$ source=Member[Foo].Method[foo].ReturnValue sink=Member[Foo].Method[foo].Argument[0] sink=Member[Foo].Method[foo].Argument[b:]
|
||||
|
||||
def userDefinedFunction(x, y)
|
||||
x.noApiGraph(y)
|
||||
x.customEntryPointCall(y) #$ call=entryPoint("CustomEntryPointCall") use=entryPoint("CustomEntryPointCall").getReturn() rhs=entryPoint("CustomEntryPointCall").getParameter(0)
|
||||
x.customEntryPointUse(y) #$ use=entryPoint("CustomEntryPointUse")
|
||||
x.customEntryPointCall(y) #$ call=EntryPoint[CustomEntryPointCall] source=EntryPoint[CustomEntryPointCall].ReturnValue sink=EntryPoint[CustomEntryPointCall].Parameter[0]
|
||||
x.customEntryPointUse(y) #$ source=EntryPoint[CustomEntryPointUse]
|
||||
end
|
||||
|
||||
array = [A::B::C] #$ use=getMember("Array").getMethod("[]").getReturn()
|
||||
array[0].m #$ use=getMember("A").getMember("B").getMember("C").getMethod("m").getReturn()
|
||||
array = [A::B::C] #$ source=Member[Array].MethodBracket.ReturnValue
|
||||
array[0].m #$ source=Member[A].Member[B].Member[C].Method[m].ReturnValue source=Member[Array].MethodBracket.ReturnValue.Element[0].Method[m].ReturnValue
|
||||
|
||||
A::B::C[0] #$ use=getMember("A").getMember("B").getMember("C").getContent(element_0)
|
||||
A::B::C[0] #$ source=Member[A].Member[B].Member[C].Element[0]
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import codeql.ruby.AST
|
||||
import codeql.ruby.DataFlow
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import codeql.ruby.ApiGraphs
|
||||
|
||||
class CustomEntryPointCall extends API::EntryPoint {
|
||||
CustomEntryPointCall() { this = "CustomEntryPointCall" }
|
||||
|
||||
override DataFlow::CallNode getACall() { result.getMethodName() = "customEntryPointCall" }
|
||||
}
|
||||
|
||||
class CustomEntryPointUse extends API::EntryPoint {
|
||||
CustomEntryPointUse() { this = "CustomEntryPointUse" }
|
||||
|
||||
override DataFlow::LocalSourceNode getASource() {
|
||||
result.(DataFlow::CallNode).getMethodName() = "customEntryPointUse"
|
||||
}
|
||||
}
|
||||
|
||||
module ApiUseTest implements TestSig {
|
||||
string getARelevantTag() { result = ["use", "def", "call"] }
|
||||
|
||||
private predicate relevantNode(API::Node a, DataFlow::Node n, Location l, string tag) {
|
||||
l = n.getLocation() and
|
||||
(
|
||||
tag = "use" and
|
||||
n = a.getAValueReachableFromSource()
|
||||
or
|
||||
tag = "def" and
|
||||
n = a.asSink()
|
||||
or
|
||||
tag = "call" and
|
||||
n = a.(API::MethodAccessNode).getCallNode()
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "use" and // def tags are always optional
|
||||
exists(DataFlow::Node n | relevantNode(_, n, location, tag) |
|
||||
// Only report the longest path on this line:
|
||||
value =
|
||||
max(API::Node a2, Location l2, DataFlow::Node n2 |
|
||||
relevantNode(a2, n2, l2, tag) and
|
||||
l2.getFile() = location.getFile() and
|
||||
l2.getEndLine() = location.getEndLine()
|
||||
|
|
||||
a2.getPath()
|
||||
order by
|
||||
size(n2.asExpr().getExpr()), a2.getPath().length() desc, a2.getPath() desc
|
||||
) and
|
||||
element = n.toString()
|
||||
)
|
||||
}
|
||||
|
||||
// We also permit optional annotations for any other path on the line.
|
||||
// This is used to test subclass paths, which typically have a shorter canonical path.
|
||||
predicate hasOptionalResult(Location location, string element, string tag, string value) {
|
||||
exists(API::Node a, DataFlow::Node n | relevantNode(a, n, location, tag) |
|
||||
element = n.toString() and
|
||||
value = getAPath(a, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<ApiUseTest>
|
||||
|
||||
private int size(AstNode n) { not n instanceof StmtSequence and result = count(n.getAChild*()) }
|
||||
|
||||
/**
|
||||
* Gets a path of the given `length` from the root to the given node.
|
||||
* This is a copy of `API::getAPath()` without the restriction on path length,
|
||||
* which would otherwise rule out paths involving `getASubclass()`.
|
||||
*/
|
||||
string getAPath(API::Node node, int length) {
|
||||
node instanceof API::Root and
|
||||
length = 0 and
|
||||
result = ""
|
||||
or
|
||||
exists(API::Node pred, API::Label::ApiLabel lbl, string predpath |
|
||||
pred.getASuccessor(lbl) = node and
|
||||
predpath = getAPath(pred, length - 1) and
|
||||
exists(string dot | if length = 1 then dot = "" else dot = "." |
|
||||
result = predpath + dot + lbl and
|
||||
// avoid producing strings longer than 1MB
|
||||
result.length() < 1000 * 1000
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -2816,6 +2816,7 @@
|
||||
| file://:0:0:0:0 | [summary param] position 0 in Mysql2::Client.escape() | file://:0:0:0:0 | [summary] to write: ReturnValue in Mysql2::Client.escape() |
|
||||
| file://:0:0:0:0 | [summary param] position 0 in Mysql2::Client.new() | file://:0:0:0:0 | [summary] to write: ReturnValue in Mysql2::Client.new() |
|
||||
| file://:0:0:0:0 | [summary param] position 0 in PG.new() | file://:0:0:0:0 | [summary] to write: ReturnValue in PG.new() |
|
||||
| file://:0:0:0:0 | [summary param] position 0 in Rack::Utils.parse_query | file://:0:0:0:0 | [summary] to write: ReturnValue in Rack::Utils.parse_query |
|
||||
| file://:0:0:0:0 | [summary param] position 0 in SQLite3::Database.quote() | file://:0:0:0:0 | [summary] to write: ReturnValue in SQLite3::Database.quote() |
|
||||
| file://:0:0:0:0 | [summary param] position 0 in Sequel.connect | file://:0:0:0:0 | [summary] to write: ReturnValue in Sequel.connect |
|
||||
| file://:0:0:0:0 | [summary param] position 0 in String.try_convert | file://:0:0:0:0 | [summary] to write: ReturnValue in String.try_convert |
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
sourceTest
|
||||
| hello_world_server.rb:8:13:8:15 | req |
|
||||
| hello_world_server.rb:32:18:32:20 | req |
|
||||
ssrfSinkTest
|
||||
| hello_world_client.rb:6:47:6:75 | "http://localhost:8080/twirp" |
|
||||
serviceInstantiationTest
|
||||
| hello_world_server.rb:24:11:24:61 | call to new |
|
||||
| hello_world_server.rb:38:1:38:57 | call to new |
|
||||
|
||||
@@ -5,4 +5,4 @@ query predicate sourceTest(Twirp::UnmarshaledParameter source) { any() }
|
||||
|
||||
query predicate ssrfSinkTest(Twirp::ServiceUrlAsSsrfSink sink) { any() }
|
||||
|
||||
query predicate serviceInstantiationTest(Twirp::ServiceInstantiation si) { any() }
|
||||
deprecated query predicate serviceInstantiationTest(Twirp::ServiceInstantiation si) { any() }
|
||||
|
||||
@@ -5,7 +5,7 @@ require_relative 'hello_world/service_twirp.rb'
|
||||
|
||||
class HelloWorldHandler
|
||||
# test: request
|
||||
def hello(req, env)
|
||||
def hello(req, env)
|
||||
puts ">> Hello #{req.name}"
|
||||
{message: "Hello #{req.name}"}
|
||||
end
|
||||
@@ -13,7 +13,7 @@ end
|
||||
|
||||
class FakeHelloWorldHandler
|
||||
# test: !request
|
||||
def hello(req, env)
|
||||
def hello(req, env)
|
||||
puts ">> Hello #{req.name}"
|
||||
{message: "Hello #{req.name}"}
|
||||
end
|
||||
@@ -21,9 +21,18 @@ end
|
||||
|
||||
handler = HelloWorldHandler.new()
|
||||
# test: serviceInstantiation
|
||||
service = Example::HelloWorld::HelloWorldService.new(handler)
|
||||
service = Example::HelloWorld::HelloWorldService.new(handler)
|
||||
|
||||
path_prefix = "/twirp/" + service.full_name
|
||||
server = WEBrick::HTTPServer.new(Port: 8080)
|
||||
server.mount path_prefix, Rack::Handler::WEBrick, service
|
||||
server.start
|
||||
|
||||
class StaticHandler
|
||||
def self.hello(req, env)
|
||||
puts ">> Hello #{req.name}"
|
||||
{message: "Hello #{req.name}"}
|
||||
end
|
||||
end
|
||||
|
||||
Example::HelloWorld::HelloWorldService.new(StaticHandler)
|
||||
|
||||
@@ -55,12 +55,12 @@ underscore
|
||||
| LotsOfCapitalLetters | lots_of_capital_letters |
|
||||
| invalid | invalid |
|
||||
mimeTypeInstances
|
||||
| mime_type.rb:2:6:2:28 | Use getMember("Mime").getContent(element_text/html) |
|
||||
| mime_type.rb:3:6:3:32 | Use getMember("Mime").getMember("Type").getMethod("new").getReturn() |
|
||||
| mime_type.rb:4:6:4:35 | Use getMember("Mime").getMember("Type").getMethod("lookup").getReturn() |
|
||||
| mime_type.rb:5:6:5:43 | Use getMember("Mime").getMember("Type").getMethod("lookup_by_extension").getReturn() |
|
||||
| mime_type.rb:6:6:6:47 | Use getMember("Mime").getMember("Type").getMethod("register").getReturn() |
|
||||
| mime_type.rb:7:6:7:64 | Use getMember("Mime").getMember("Type").getMethod("register_alias").getReturn() |
|
||||
| mime_type.rb:2:6:2:28 | ForwardNode(call to fetch) |
|
||||
| mime_type.rb:3:6:3:32 | ForwardNode(call to new) |
|
||||
| mime_type.rb:4:6:4:35 | ForwardNode(call to lookup) |
|
||||
| mime_type.rb:5:6:5:43 | ForwardNode(call to lookup_by_extension) |
|
||||
| mime_type.rb:6:6:6:47 | ForwardNode(call to register) |
|
||||
| mime_type.rb:7:6:7:64 | ForwardNode(call to register_alias) |
|
||||
mimeTypeMatchRegExpInterpretations
|
||||
| mime_type.rb:11:11:11:19 | "foo/bar" |
|
||||
| mime_type.rb:12:7:12:15 | "foo/bar" |
|
||||
|
||||
@@ -10,6 +10,7 @@ activeRecordInstances
|
||||
| ActiveRecord.rb:9:5:9:68 | call to find |
|
||||
| ActiveRecord.rb:13:5:13:40 | call to find_by |
|
||||
| ActiveRecord.rb:13:5:13:46 | call to users |
|
||||
| ActiveRecord.rb:35:5:35:51 | call to authenticate |
|
||||
| ActiveRecord.rb:36:5:36:30 | call to find_by_name |
|
||||
| ActiveRecord.rb:55:5:57:7 | if ... |
|
||||
| ActiveRecord.rb:55:43:56:40 | then ... |
|
||||
@@ -107,12 +108,14 @@ activeRecordSqlExecutionRanges
|
||||
| ActiveRecord.rb:19:16:19:24 | condition |
|
||||
| ActiveRecord.rb:28:30:28:44 | ...[...] |
|
||||
| ActiveRecord.rb:29:20:29:42 | "id = '#{...}'" |
|
||||
| ActiveRecord.rb:30:21:30:45 | call to [] |
|
||||
| ActiveRecord.rb:30:22:30:44 | "id = '#{...}'" |
|
||||
| ActiveRecord.rb:31:16:31:21 | <<-SQL |
|
||||
| ActiveRecord.rb:34:20:34:47 | "user.id = '#{...}'" |
|
||||
| ActiveRecord.rb:46:20:46:32 | ... + ... |
|
||||
| ActiveRecord.rb:52:16:52:28 | "name #{...}" |
|
||||
| ActiveRecord.rb:56:20:56:39 | "username = #{...}" |
|
||||
| ActiveRecord.rb:68:21:68:44 | ...[...] |
|
||||
| ActiveRecord.rb:106:27:106:76 | "this is an unsafe annotation:..." |
|
||||
activeRecordModelClassMethodCalls
|
||||
| ActiveRecord.rb:2:3:2:17 | call to has_many |
|
||||
@@ -127,7 +130,6 @@ activeRecordModelClassMethodCalls
|
||||
| ActiveRecord.rb:31:5:31:35 | call to where |
|
||||
| ActiveRecord.rb:34:5:34:14 | call to where |
|
||||
| ActiveRecord.rb:34:5:34:48 | call to not |
|
||||
| ActiveRecord.rb:35:5:35:51 | call to authenticate |
|
||||
| ActiveRecord.rb:36:5:36:30 | call to find_by_name |
|
||||
| ActiveRecord.rb:37:5:37:36 | call to not_a_find_by_method |
|
||||
| ActiveRecord.rb:46:5:46:33 | call to delete_by |
|
||||
@@ -135,7 +137,6 @@ activeRecordModelClassMethodCalls
|
||||
| ActiveRecord.rb:56:7:56:40 | call to find_by |
|
||||
| ActiveRecord.rb:60:5:60:33 | call to find_by |
|
||||
| ActiveRecord.rb:62:5:62:34 | call to find |
|
||||
| ActiveRecord.rb:68:5:68:45 | call to delete_by |
|
||||
| ActiveRecord.rb:72:5:72:24 | call to create |
|
||||
| ActiveRecord.rb:76:5:76:66 | call to create |
|
||||
| ActiveRecord.rb:80:5:80:68 | call to create |
|
||||
@@ -152,6 +153,96 @@ activeRecordModelClassMethodCalls
|
||||
| associations.rb:12:3:12:32 | call to has_and_belongs_to_many |
|
||||
| associations.rb:16:3:16:18 | call to belongs_to |
|
||||
| associations.rb:19:11:19:20 | call to new |
|
||||
| associations.rb:21:9:21:21 | call to posts |
|
||||
| associations.rb:21:9:21:28 | call to create |
|
||||
| associations.rb:23:12:23:25 | call to comments |
|
||||
| associations.rb:23:12:23:32 | call to create |
|
||||
| associations.rb:25:11:25:22 | call to author |
|
||||
| associations.rb:27:9:27:21 | call to posts |
|
||||
| associations.rb:27:9:27:28 | call to create |
|
||||
| associations.rb:29:1:29:13 | call to posts |
|
||||
| associations.rb:29:1:29:22 | ... << ... |
|
||||
| associations.rb:31:1:31:12 | call to author= |
|
||||
| associations.rb:35:1:35:14 | call to comments |
|
||||
| associations.rb:35:1:35:21 | call to create |
|
||||
| associations.rb:35:1:35:28 | call to create |
|
||||
| associations.rb:37:1:37:13 | call to posts |
|
||||
| associations.rb:37:1:37:20 | call to reload |
|
||||
| associations.rb:37:1:37:27 | call to create |
|
||||
| associations.rb:39:1:39:15 | call to build_tag |
|
||||
| associations.rb:40:1:40:15 | call to build_tag |
|
||||
| associations.rb:42:1:42:13 | call to posts |
|
||||
| associations.rb:42:1:42:25 | call to push |
|
||||
| associations.rb:43:1:43:13 | call to posts |
|
||||
| associations.rb:43:1:43:27 | call to concat |
|
||||
| associations.rb:44:1:44:13 | call to posts |
|
||||
| associations.rb:44:1:44:19 | call to build |
|
||||
| associations.rb:45:1:45:13 | call to posts |
|
||||
| associations.rb:45:1:45:20 | call to create |
|
||||
| associations.rb:46:1:46:13 | call to posts |
|
||||
| associations.rb:46:1:46:21 | call to create! |
|
||||
| associations.rb:47:1:47:13 | call to posts |
|
||||
| associations.rb:47:1:47:20 | call to delete |
|
||||
| associations.rb:48:1:48:13 | call to posts |
|
||||
| associations.rb:48:1:48:24 | call to delete_all |
|
||||
| associations.rb:49:1:49:13 | call to posts |
|
||||
| associations.rb:49:1:49:21 | call to destroy |
|
||||
| associations.rb:50:1:50:13 | call to posts |
|
||||
| associations.rb:50:1:50:25 | call to destroy_all |
|
||||
| associations.rb:51:1:51:13 | call to posts |
|
||||
| associations.rb:51:1:51:22 | call to distinct |
|
||||
| associations.rb:51:1:51:36 | call to find |
|
||||
| associations.rb:52:1:52:13 | call to posts |
|
||||
| associations.rb:52:1:52:19 | call to reset |
|
||||
| associations.rb:52:1:52:33 | call to find |
|
||||
| associations.rb:53:1:53:13 | call to posts |
|
||||
| associations.rb:53:1:53:20 | call to reload |
|
||||
| associations.rb:53:1:53:34 | call to find |
|
||||
activeRecordModelClassMethodCallsReplacement
|
||||
| ActiveRecord.rb:1:1:3:3 | UserGroup | ActiveRecord.rb:2:3:2:17 | call to has_many |
|
||||
| ActiveRecord.rb:1:1:3:3 | UserGroup | ActiveRecord.rb:13:5:13:40 | call to find_by |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:6:3:6:24 | call to belongs_to |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:9:5:9:68 | call to find |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:19:5:19:25 | call to destroy_by |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:28:5:28:45 | call to calculate |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:29:5:29:43 | call to delete_by |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:30:5:30:46 | call to destroy_by |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:31:5:31:35 | call to where |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:34:5:34:14 | call to where |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:35:5:35:51 | call to authenticate |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:36:5:36:30 | call to find_by_name |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:37:5:37:36 | call to not_a_find_by_method |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:46:5:46:33 | call to delete_by |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:52:5:52:29 | call to order |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:56:7:56:40 | call to find_by |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:60:5:60:33 | call to find_by |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:62:5:62:34 | call to find |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:68:5:68:45 | call to delete_by |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:72:5:72:24 | call to create |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:76:5:76:66 | call to create |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:80:5:80:68 | call to create |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:84:5:84:16 | call to create |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:88:5:88:27 | call to update |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:92:5:92:69 | call to update |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:96:5:96:71 | call to update |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:102:13:102:54 | call to annotate |
|
||||
| ActiveRecord.rb:5:1:15:3 | User | ActiveRecord.rb:106:13:106:77 | call to annotate |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:19:5:19:25 | call to destroy_by |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:68:5:68:45 | call to delete_by |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:72:5:72:24 | call to create |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:76:5:76:66 | call to create |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:80:5:80:68 | call to create |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:84:5:84:16 | call to create |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:88:5:88:27 | call to update |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:92:5:92:69 | call to update |
|
||||
| ActiveRecord.rb:17:1:21:3 | Admin | ActiveRecord.rb:96:5:96:71 | call to update |
|
||||
| associations.rb:1:1:3:3 | Author | associations.rb:2:3:2:17 | call to has_many |
|
||||
| associations.rb:1:1:3:3 | Author | associations.rb:19:11:19:20 | call to new |
|
||||
| associations.rb:5:1:9:3 | Post | associations.rb:6:3:6:20 | call to belongs_to |
|
||||
| associations.rb:5:1:9:3 | Post | associations.rb:7:3:7:20 | call to has_many |
|
||||
| associations.rb:5:1:9:3 | Post | associations.rb:8:3:8:31 | call to has_and_belongs_to_many |
|
||||
| associations.rb:11:1:13:3 | Tag | associations.rb:12:3:12:32 | call to has_and_belongs_to_many |
|
||||
| associations.rb:15:1:17:3 | Comment | associations.rb:16:3:16:18 | call to belongs_to |
|
||||
potentiallyUnsafeSqlExecutingMethodCall
|
||||
| ActiveRecord.rb:9:5:9:68 | call to find |
|
||||
| ActiveRecord.rb:19:5:19:25 | call to destroy_by |
|
||||
|
||||
@@ -9,9 +9,19 @@ query predicate activeRecordInstances(ActiveRecordInstance i) { any() }
|
||||
|
||||
query predicate activeRecordSqlExecutionRanges(ActiveRecordSqlExecutionRange range) { any() }
|
||||
|
||||
query predicate activeRecordModelClassMethodCalls(ActiveRecordModelClassMethodCall call) { any() }
|
||||
deprecated query predicate activeRecordModelClassMethodCalls(ActiveRecordModelClassMethodCall call) {
|
||||
any()
|
||||
}
|
||||
|
||||
query predicate potentiallyUnsafeSqlExecutingMethodCall(PotentiallyUnsafeSqlExecutingMethodCall call) {
|
||||
query predicate activeRecordModelClassMethodCallsReplacement(
|
||||
ActiveRecordModelClass cls, DataFlow::CallNode call
|
||||
) {
|
||||
call = cls.getClassNode().trackModule().getAMethodCall(_)
|
||||
}
|
||||
|
||||
deprecated query predicate potentiallyUnsafeSqlExecutingMethodCall(
|
||||
PotentiallyUnsafeSqlExecutingMethodCall call
|
||||
) {
|
||||
any()
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,13 @@ modelInstances
|
||||
| active_resource.rb:26:9:26:14 | people |
|
||||
| active_resource.rb:26:9:26:20 | call to first |
|
||||
| active_resource.rb:27:1:27:5 | alice |
|
||||
modelInstancesAsSource
|
||||
| active_resource.rb:1:1:3:3 | Person | active_resource.rb:5:9:5:33 | call to new |
|
||||
| active_resource.rb:1:1:3:3 | Person | active_resource.rb:8:9:8:22 | call to find |
|
||||
| active_resource.rb:1:1:3:3 | Person | active_resource.rb:16:1:16:23 | call to new |
|
||||
| active_resource.rb:1:1:3:3 | Person | active_resource.rb:18:1:18:22 | call to get |
|
||||
| active_resource.rb:1:1:3:3 | Person | active_resource.rb:24:10:24:26 | call to find |
|
||||
| active_resource.rb:1:1:3:3 | Person | active_resource.rb:26:9:26:20 | call to first |
|
||||
modelInstanceMethodCalls
|
||||
| active_resource.rb:6:1:6:10 | call to save |
|
||||
| active_resource.rb:9:1:9:13 | call to address= |
|
||||
@@ -50,3 +57,6 @@ collections
|
||||
| active_resource.rb:24:1:24:26 | ... = ... |
|
||||
| active_resource.rb:24:10:24:26 | call to find |
|
||||
| active_resource.rb:26:9:26:14 | people |
|
||||
collectionSources
|
||||
| active_resource.rb:23:10:23:19 | call to all |
|
||||
| active_resource.rb:24:10:24:26 | call to find |
|
||||
|
||||
@@ -3,7 +3,8 @@ import codeql.ruby.DataFlow
|
||||
import codeql.ruby.frameworks.ActiveResource
|
||||
|
||||
query predicate modelClasses(
|
||||
ActiveResource::ModelClass c, DataFlow::Node siteAssignCall, boolean disablesCertificateValidation
|
||||
ActiveResource::ModelClassNode c, DataFlow::Node siteAssignCall,
|
||||
boolean disablesCertificateValidation
|
||||
) {
|
||||
c.getASiteAssignment() = siteAssignCall and
|
||||
if c.disablesCertificateValidation(siteAssignCall)
|
||||
@@ -13,8 +14,16 @@ query predicate modelClasses(
|
||||
|
||||
query predicate modelClassMethodCalls(ActiveResource::ModelClassMethodCall c) { any() }
|
||||
|
||||
query predicate modelInstances(ActiveResource::ModelInstance c) { any() }
|
||||
deprecated query predicate modelInstances(ActiveResource::ModelInstance c) { any() }
|
||||
|
||||
query predicate modelInstancesAsSource(
|
||||
ActiveResource::ModelClassNode cls, DataFlow::LocalSourceNode node
|
||||
) {
|
||||
node = cls.getAnInstanceReference().asSource()
|
||||
}
|
||||
|
||||
query predicate modelInstanceMethodCalls(ActiveResource::ModelInstanceMethodCall c) { any() }
|
||||
|
||||
query predicate collections(ActiveResource::Collection c) { any() }
|
||||
deprecated query predicate collections(ActiveResource::Collection c) { any() }
|
||||
|
||||
query predicate collectionSources(ActiveResource::CollectionSource c) { any() }
|
||||
|
||||
@@ -6,7 +6,9 @@ rackRequestHandlers
|
||||
| rack.rb:60:3:62:5 | call | rack.rb:60:12:60:14 | env | rack.rb:66:7:66:24 | call to [] |
|
||||
| rack.rb:60:3:62:5 | call | rack.rb:60:12:60:14 | env | rack.rb:73:5:73:23 | call to [] |
|
||||
| rack.rb:79:3:81:5 | call | rack.rb:79:17:79:19 | env | rack.rb:93:5:93:78 | call to finish |
|
||||
| rack.rb:98:3:102:5 | call | rack.rb:98:12:98:14 | env | rack.rb:101:5:101:42 | call to [] |
|
||||
| rack.rb:98:3:107:5 | call | rack.rb:98:12:98:14 | env | rack.rb:110:5:110:28 | call to [] |
|
||||
| rack.rb:98:3:107:5 | call | rack.rb:98:12:98:14 | env | rack.rb:114:5:114:30 | call to [] |
|
||||
| rack.rb:119:3:123:5 | call | rack.rb:119:12:119:14 | env | rack.rb:122:5:122:42 | call to [] |
|
||||
| rack_apps.rb:6:3:12:5 | call | rack_apps.rb:6:12:6:14 | env | rack_apps.rb:10:12:10:34 | call to [] |
|
||||
| rack_apps.rb:16:3:18:5 | call | rack_apps.rb:16:17:16:19 | env | rack_apps.rb:17:5:17:28 | call to [] |
|
||||
| rack_apps.rb:21:14:21:50 | -> { ... } | rack_apps.rb:21:17:21:19 | env | rack_apps.rb:21:24:21:48 | call to [] |
|
||||
@@ -18,4 +20,7 @@ redirectResponses
|
||||
| rack.rb:43:5:43:45 | call to [] | rack.rb:42:30:42:40 | "/foo.html" |
|
||||
| rack.rb:93:5:93:78 | call to finish | rack.rb:93:60:93:70 | redirect_to |
|
||||
requestInputAccesses
|
||||
| rack.rb:99:14:99:32 | ...[...] |
|
||||
| rack.rb:100:18:100:28 | call to cookies |
|
||||
| rack.rb:103:14:103:23 | call to params |
|
||||
| rack.rb:104:18:104:32 | ...[...] |
|
||||
| rack.rb:120:14:120:32 | ...[...] |
|
||||
|
||||
@@ -94,6 +94,27 @@ class Qux
|
||||
end
|
||||
end
|
||||
|
||||
class UsesRequest
|
||||
def call(env)
|
||||
req = Rack::Request.new(env)
|
||||
if session = req.cookies['session']
|
||||
reuse_session(session)
|
||||
else
|
||||
name = req.params['name']
|
||||
password = req['password']
|
||||
login(name, password)
|
||||
end
|
||||
end
|
||||
|
||||
def login(name, password)
|
||||
[200, {}, "new session"]
|
||||
end
|
||||
|
||||
def reuse_session(name, password)
|
||||
[200, {}, "reuse session"]
|
||||
end
|
||||
end
|
||||
|
||||
class UsesEnvQueryParams
|
||||
def call(env)
|
||||
params = env['QUERY_STRING']
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
require 'libxml'
|
||||
|
||||
class FooController < ActionController::Base
|
||||
def libxml_handler(event:, context:)
|
||||
name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
<foo>bar</foo>
|
||||
<password>THIS IS SECRET</password>
|
||||
</root>
|
||||
XML
|
||||
|
||||
# Parse the XML
|
||||
doc = LibXML::XML::Document.string(xml)
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results1 = doc.find_first('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results2 = doc.find_first("//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results3 = doc.find('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results4 = doc.find("//#{name}")
|
||||
end
|
||||
end
|
||||
|
||||
class BarController < ActionController::Base
|
||||
def libxml_safe_handler(event:, context:)
|
||||
safe_name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
<foo>bar</foo>
|
||||
<password>THIS IS SECRET</password>
|
||||
</root>
|
||||
XML
|
||||
|
||||
# Parse the XML
|
||||
doc = REXML::Document.new(xml)
|
||||
|
||||
# GOOD: barrier guard prevents taint flow
|
||||
safe_name = if ["foo", "foo2"].include? safe_name
|
||||
safe_name
|
||||
else
|
||||
safe_name = "foo"
|
||||
end
|
||||
|
||||
# GOOD: XPath query is not constructed from unsanitized user input
|
||||
results5 = doc.find_first("//#{safe_name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from unsanitized user input
|
||||
results6 = doc.find("//#{safe_name}")
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,88 @@
|
||||
require 'nokogiri'
|
||||
|
||||
class FooController < ActionController::Base
|
||||
def nokogiri_handler(event:, context:)
|
||||
name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
<foo>bar</foo>
|
||||
<password>THIS IS SECRET</password>
|
||||
</root>
|
||||
XML
|
||||
|
||||
# Parse the XML
|
||||
doc = Nokogiri::XML.parse(xml)
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results1 = doc.at('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results2 = doc.at("//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results3 = doc.xpath('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results4 = doc.xpath("//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results5 = doc.at_xpath('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results6 = doc.at_xpath("//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
doc.xpath('//foo').each do |element|
|
||||
puts element.text
|
||||
end
|
||||
|
||||
# BAD: XPath query constructed from user input
|
||||
doc.xpath("//#{name}").each do |element|
|
||||
puts element.text
|
||||
end
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
doc.search('//foo').each do |element|
|
||||
puts element.text
|
||||
end
|
||||
|
||||
# BAD: XPath query constructed from user input
|
||||
doc.search("//#{name}").each do |element|
|
||||
puts element.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BarController < ActionController::Base
|
||||
def nokogiri_safe_handler(event:, context:)
|
||||
safe_name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
<foo>bar</foo>
|
||||
<password>THIS IS SECRET</password>
|
||||
</root>
|
||||
XML
|
||||
|
||||
# Parse the XML
|
||||
doc = Nokogiri::XML.parse(xml)
|
||||
|
||||
# GOOD: barrier guard prevents taint flow
|
||||
safe_name = if ["foo", "foo2"].include? safe_name
|
||||
safe_name
|
||||
else
|
||||
safe_name = "foo"
|
||||
end
|
||||
|
||||
# GOOD: XPath query is not constructed from unsanitized user input
|
||||
results7 = doc.at("//#{safe_name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from unsanitized user input
|
||||
results8 = doc.xpath("//#{safe_name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from unsanitized user input
|
||||
results9 = doc.at_xpath("//#{safe_name}")
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,69 @@
|
||||
require 'rexml'
|
||||
|
||||
class FooController < ActionController::Base
|
||||
def rexml_handler(event:, context:)
|
||||
name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
<foo>bar</foo>
|
||||
<password>THIS IS SECRET</password>
|
||||
</root>
|
||||
XML
|
||||
|
||||
# Parse the XML
|
||||
doc = REXML::Document.new(xml)
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results1 = REXML::XPath.first(doc, "//foo")
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results2 = REXML::XPath.first(doc, "//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results3 = REXML::XPath.match(doc, "//foo", nil)
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results4 = REXML::XPath.match(doc, "//#{name}", nil)
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
REXML::XPath.each(doc, "//foo") do |element|
|
||||
puts element.text
|
||||
end
|
||||
|
||||
# BAD: XPath query constructed from user input
|
||||
REXML::XPath.each(doc, "//#{name}") do |element|
|
||||
puts element.text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BarController < ActionController::Base
|
||||
def rexml_safe_handler(event:, context:)
|
||||
safe_name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
<foo>bar</foo>
|
||||
<password>THIS IS SECRET</password>
|
||||
</root>
|
||||
XML
|
||||
|
||||
# Parse the XML
|
||||
doc = REXML::Document.new(xml)
|
||||
|
||||
# GOOD: barrier guard prevents taint flow
|
||||
safe_name = if ["foo", "foo2"].include? safe_name
|
||||
safe_name
|
||||
else
|
||||
safe_name = "foo"
|
||||
end
|
||||
|
||||
# GOOD: XPath query is not constructed from unsanitized user input
|
||||
results5 = REXML::XPath.first(doc, "//#{safe_name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from unsanitized user input
|
||||
results6 = REXML::XPath.match(doc, "//#{safe_name}", nil)
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
edges
|
||||
| LibxmlInjection.rb:5:5:5:8 | name | LibxmlInjection.rb:21:31:21:41 | "//#{...}" |
|
||||
| LibxmlInjection.rb:5:5:5:8 | name | LibxmlInjection.rb:27:25:27:35 | "//#{...}" |
|
||||
| LibxmlInjection.rb:5:12:5:17 | call to params | LibxmlInjection.rb:5:12:5:29 | ...[...] |
|
||||
| LibxmlInjection.rb:5:12:5:29 | ...[...] | LibxmlInjection.rb:5:5:5:8 | name |
|
||||
| NokogiriInjection.rb:5:5:5:8 | name | NokogiriInjection.rb:21:23:21:33 | "//#{...}" |
|
||||
| NokogiriInjection.rb:5:5:5:8 | name | NokogiriInjection.rb:27:26:27:36 | "//#{...}" |
|
||||
| NokogiriInjection.rb:5:5:5:8 | name | NokogiriInjection.rb:33:29:33:39 | "//#{...}" |
|
||||
| NokogiriInjection.rb:5:5:5:8 | name | NokogiriInjection.rb:41:15:41:25 | "//#{...}" |
|
||||
| NokogiriInjection.rb:5:5:5:8 | name | NokogiriInjection.rb:51:16:51:26 | "//#{...}" |
|
||||
| NokogiriInjection.rb:5:12:5:17 | call to params | NokogiriInjection.rb:5:12:5:29 | ...[...] |
|
||||
| NokogiriInjection.rb:5:12:5:29 | ...[...] | NokogiriInjection.rb:5:5:5:8 | name |
|
||||
| RexmlInjection.rb:5:5:5:8 | name | RexmlInjection.rb:21:40:21:50 | "//#{...}" |
|
||||
| RexmlInjection.rb:5:5:5:8 | name | RexmlInjection.rb:27:40:27:50 | "//#{...}" |
|
||||
| RexmlInjection.rb:5:5:5:8 | name | RexmlInjection.rb:35:28:35:38 | "//#{...}" |
|
||||
| RexmlInjection.rb:5:12:5:17 | call to params | RexmlInjection.rb:5:12:5:29 | ...[...] |
|
||||
| RexmlInjection.rb:5:12:5:29 | ...[...] | RexmlInjection.rb:5:5:5:8 | name |
|
||||
nodes
|
||||
| LibxmlInjection.rb:5:5:5:8 | name | semmle.label | name |
|
||||
| LibxmlInjection.rb:5:12:5:17 | call to params | semmle.label | call to params |
|
||||
| LibxmlInjection.rb:5:12:5:29 | ...[...] | semmle.label | ...[...] |
|
||||
| LibxmlInjection.rb:21:31:21:41 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| LibxmlInjection.rb:27:25:27:35 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| NokogiriInjection.rb:5:5:5:8 | name | semmle.label | name |
|
||||
| NokogiriInjection.rb:5:12:5:17 | call to params | semmle.label | call to params |
|
||||
| NokogiriInjection.rb:5:12:5:29 | ...[...] | semmle.label | ...[...] |
|
||||
| NokogiriInjection.rb:21:23:21:33 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| NokogiriInjection.rb:27:26:27:36 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| NokogiriInjection.rb:33:29:33:39 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| NokogiriInjection.rb:41:15:41:25 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| NokogiriInjection.rb:51:16:51:26 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| RexmlInjection.rb:5:5:5:8 | name | semmle.label | name |
|
||||
| RexmlInjection.rb:5:12:5:17 | call to params | semmle.label | call to params |
|
||||
| RexmlInjection.rb:5:12:5:29 | ...[...] | semmle.label | ...[...] |
|
||||
| RexmlInjection.rb:21:40:21:50 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| RexmlInjection.rb:27:40:27:50 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
| RexmlInjection.rb:35:28:35:38 | "//#{...}" | semmle.label | "//#{...}" |
|
||||
subpaths
|
||||
#select
|
||||
| LibxmlInjection.rb:21:31:21:41 | "//#{...}" | LibxmlInjection.rb:5:12:5:17 | call to params | LibxmlInjection.rb:21:31:21:41 | "//#{...}" | XPath expression depends on a $@. | LibxmlInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| LibxmlInjection.rb:27:25:27:35 | "//#{...}" | LibxmlInjection.rb:5:12:5:17 | call to params | LibxmlInjection.rb:27:25:27:35 | "//#{...}" | XPath expression depends on a $@. | LibxmlInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| NokogiriInjection.rb:21:23:21:33 | "//#{...}" | NokogiriInjection.rb:5:12:5:17 | call to params | NokogiriInjection.rb:21:23:21:33 | "//#{...}" | XPath expression depends on a $@. | NokogiriInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| NokogiriInjection.rb:27:26:27:36 | "//#{...}" | NokogiriInjection.rb:5:12:5:17 | call to params | NokogiriInjection.rb:27:26:27:36 | "//#{...}" | XPath expression depends on a $@. | NokogiriInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| NokogiriInjection.rb:33:29:33:39 | "//#{...}" | NokogiriInjection.rb:5:12:5:17 | call to params | NokogiriInjection.rb:33:29:33:39 | "//#{...}" | XPath expression depends on a $@. | NokogiriInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| NokogiriInjection.rb:41:15:41:25 | "//#{...}" | NokogiriInjection.rb:5:12:5:17 | call to params | NokogiriInjection.rb:41:15:41:25 | "//#{...}" | XPath expression depends on a $@. | NokogiriInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| NokogiriInjection.rb:51:16:51:26 | "//#{...}" | NokogiriInjection.rb:5:12:5:17 | call to params | NokogiriInjection.rb:51:16:51:26 | "//#{...}" | XPath expression depends on a $@. | NokogiriInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| RexmlInjection.rb:21:40:21:50 | "//#{...}" | RexmlInjection.rb:5:12:5:17 | call to params | RexmlInjection.rb:21:40:21:50 | "//#{...}" | XPath expression depends on a $@. | RexmlInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| RexmlInjection.rb:27:40:27:50 | "//#{...}" | RexmlInjection.rb:5:12:5:17 | call to params | RexmlInjection.rb:27:40:27:50 | "//#{...}" | XPath expression depends on a $@. | RexmlInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
| RexmlInjection.rb:35:28:35:38 | "//#{...}" | RexmlInjection.rb:5:12:5:17 | call to params | RexmlInjection.rb:35:28:35:38 | "//#{...}" | XPath expression depends on a $@. | RexmlInjection.rb:5:12:5:17 | call to params | user-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/xpath-injection/XpathInjection.ql
|
||||
@@ -3,7 +3,6 @@ edges
|
||||
| app/controllers/foo/stores_controller.rb:8:5:8:6 | dt | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt |
|
||||
| app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/controllers/foo/stores_controller.rb:8:5:8:6 | dt |
|
||||
| app/controllers/foo/stores_controller.rb:9:22:9:23 | dt | app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text |
|
||||
| app/controllers/foo/stores_controller.rb:12:28:12:48 | call to raw_name | app/views/foo/stores/show.html.erb:82:5:82:24 | @other_user_raw_name |
|
||||
| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:2:9:2:20 | call to display_text |
|
||||
| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:5:9:5:21 | call to local_assigns [element :display_text] |
|
||||
| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:9:9:9:21 | call to local_assigns [element :display_text] |
|
||||
@@ -22,7 +21,6 @@ nodes
|
||||
| app/controllers/foo/stores_controller.rb:8:5:8:6 | dt | semmle.label | dt |
|
||||
| app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | semmle.label | call to read |
|
||||
| app/controllers/foo/stores_controller.rb:9:22:9:23 | dt | semmle.label | dt |
|
||||
| app/controllers/foo/stores_controller.rb:12:28:12:48 | call to raw_name | semmle.label | call to raw_name |
|
||||
| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | semmle.label | dt |
|
||||
| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | semmle.label | call to display_text |
|
||||
| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] |
|
||||
@@ -39,11 +37,7 @@ nodes
|
||||
| app/views/foo/stores/show.html.erb:40:64:40:87 | ... + ... | semmle.label | ... + ... |
|
||||
| app/views/foo/stores/show.html.erb:40:76:40:87 | call to display_text | semmle.label | call to display_text |
|
||||
| app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | semmle.label | call to handle |
|
||||
| app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | semmle.label | call to raw_name |
|
||||
| app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | semmle.label | call to handle |
|
||||
| app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | semmle.label | call to raw_name |
|
||||
| app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | semmle.label | call to display_name |
|
||||
| app/views/foo/stores/show.html.erb:82:5:82:24 | @other_user_raw_name | semmle.label | @other_user_raw_name |
|
||||
| app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | semmle.label | call to sprintf |
|
||||
| app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | semmle.label | call to handle |
|
||||
subpaths
|
||||
@@ -57,9 +51,5 @@ subpaths
|
||||
| app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value |
|
||||
| app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value |
|
||||
| app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | stored value |
|
||||
| app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:49:5:49:18 | call to raw_name | stored value |
|
||||
| app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | stored value |
|
||||
| app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:69:3:69:20 | call to raw_name | stored value |
|
||||
| app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:79:5:79:22 | call to display_name | stored value |
|
||||
| app/views/foo/stores/show.html.erb:82:5:82:24 | @other_user_raw_name | app/controllers/foo/stores_controller.rb:12:28:12:48 | call to raw_name | app/views/foo/stores/show.html.erb:82:5:82:24 | @other_user_raw_name | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:12:28:12:48 | call to raw_name | stored value |
|
||||
| app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | stored value |
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
some_user.handle.html_safe
|
||||
%>
|
||||
|
||||
<%# BAD: Indirect to a database value without escaping %>
|
||||
<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %>
|
||||
<%=
|
||||
some_user = User.find 1
|
||||
some_user.raw_name.html_safe
|
||||
@@ -75,10 +75,10 @@
|
||||
some_user.handle
|
||||
%>
|
||||
|
||||
<%# BAD: Indirect to a database value without escaping %>
|
||||
<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %>
|
||||
<%= @user.display_name.html_safe %>
|
||||
|
||||
<%# BAD: Indirect to a database value without escaping %>
|
||||
<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %>
|
||||
<%= @other_user_raw_name.html_safe %>
|
||||
|
||||
<%# BAD: Kernel.sprintf is a taint-step %>
|
||||
|
||||
@@ -22,6 +22,7 @@ edges
|
||||
| ActiveRecordInjection.rb:70:38:70:50 | ...[...] | ActiveRecordInjection.rb:8:31:8:34 | pass |
|
||||
| ActiveRecordInjection.rb:74:41:74:46 | call to params | ActiveRecordInjection.rb:74:41:74:51 | ...[...] |
|
||||
| ActiveRecordInjection.rb:74:41:74:51 | ...[...] | ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" |
|
||||
| ActiveRecordInjection.rb:79:23:79:28 | call to params | ActiveRecordInjection.rb:79:23:79:35 | ...[...] |
|
||||
| ActiveRecordInjection.rb:83:17:83:22 | call to params | ActiveRecordInjection.rb:83:17:83:31 | ...[...] |
|
||||
| ActiveRecordInjection.rb:84:19:84:24 | call to params | ActiveRecordInjection.rb:84:19:84:33 | ...[...] |
|
||||
| ActiveRecordInjection.rb:88:18:88:23 | call to params | ActiveRecordInjection.rb:88:18:88:35 | ...[...] |
|
||||
@@ -35,6 +36,7 @@ edges
|
||||
| ActiveRecordInjection.rb:103:11:103:17 | ...[...] | ActiveRecordInjection.rb:103:5:103:7 | uid |
|
||||
| ActiveRecordInjection.rb:104:5:104:9 | uidEq | ActiveRecordInjection.rb:108:20:108:32 | ... + ... |
|
||||
| ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] |
|
||||
| ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] |
|
||||
| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | ActiveRecordInjection.rb:20:22:20:30 | condition |
|
||||
| ActiveRecordInjection.rb:155:59:155:64 | call to params | ActiveRecordInjection.rb:155:59:155:74 | ...[...] |
|
||||
| ActiveRecordInjection.rb:155:59:155:74 | ...[...] | ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." |
|
||||
@@ -102,6 +104,8 @@ nodes
|
||||
| ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | semmle.label | "id = '#{...}'" |
|
||||
| ActiveRecordInjection.rb:74:41:74:46 | call to params | semmle.label | call to params |
|
||||
| ActiveRecordInjection.rb:74:41:74:51 | ...[...] | semmle.label | ...[...] |
|
||||
| ActiveRecordInjection.rb:79:23:79:28 | call to params | semmle.label | call to params |
|
||||
| ActiveRecordInjection.rb:79:23:79:35 | ...[...] | semmle.label | ...[...] |
|
||||
| ActiveRecordInjection.rb:83:17:83:22 | call to params | semmle.label | call to params |
|
||||
| ActiveRecordInjection.rb:83:17:83:31 | ...[...] | semmle.label | ...[...] |
|
||||
| ActiveRecordInjection.rb:84:19:84:24 | call to params | semmle.label | call to params |
|
||||
@@ -123,6 +127,7 @@ nodes
|
||||
| ActiveRecordInjection.rb:108:20:108:32 | ... + ... | semmle.label | ... + ... |
|
||||
| ActiveRecordInjection.rb:141:21:141:26 | call to params | semmle.label | call to params |
|
||||
| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | semmle.label | ...[...] |
|
||||
| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | semmle.label | ...[...] |
|
||||
| ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | semmle.label | "this is an unsafe annotation:..." |
|
||||
| ActiveRecordInjection.rb:155:59:155:64 | call to params | semmle.label | call to params |
|
||||
| ActiveRecordInjection.rb:155:59:155:74 | ...[...] | semmle.label | ...[...] |
|
||||
@@ -172,6 +177,7 @@ subpaths
|
||||
| ActiveRecordInjection.rb:61:16:61:21 | <<-SQL | ActiveRecordInjection.rb:62:21:62:26 | call to params | ActiveRecordInjection.rb:61:16:61:21 | <<-SQL | This SQL query depends on a $@. | ActiveRecordInjection.rb:62:21:62:26 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:68:20:68:47 | "user.id = '#{...}'" | ActiveRecordInjection.rb:68:34:68:39 | call to params | ActiveRecordInjection.rb:68:20:68:47 | "user.id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:68:34:68:39 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | ActiveRecordInjection.rb:74:41:74:46 | call to params | ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:74:41:74:46 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:79:23:79:35 | ...[...] | ActiveRecordInjection.rb:79:23:79:28 | call to params | ActiveRecordInjection.rb:79:23:79:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:79:23:79:28 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:83:17:83:31 | ...[...] | ActiveRecordInjection.rb:83:17:83:22 | call to params | ActiveRecordInjection.rb:83:17:83:31 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:83:17:83:22 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:84:19:84:33 | ...[...] | ActiveRecordInjection.rb:84:19:84:24 | call to params | ActiveRecordInjection.rb:84:19:84:33 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:84:19:84:24 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:88:18:88:35 | ...[...] | ActiveRecordInjection.rb:88:18:88:23 | call to params | ActiveRecordInjection.rb:88:18:88:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:88:18:88:23 | call to params | user-provided value |
|
||||
@@ -179,6 +185,7 @@ subpaths
|
||||
| ActiveRecordInjection.rb:94:18:94:35 | ...[...] | ActiveRecordInjection.rb:94:18:94:23 | call to params | ActiveRecordInjection.rb:94:18:94:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:94:18:94:23 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:96:23:96:47 | ...[...] | ActiveRecordInjection.rb:96:23:96:28 | call to params | ActiveRecordInjection.rb:96:23:96:47 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:96:23:96:28 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:108:20:108:32 | ... + ... | ActiveRecordInjection.rb:102:10:102:15 | call to params | ActiveRecordInjection.rb:108:20:108:32 | ... + ... | This SQL query depends on a $@. | ActiveRecordInjection.rb:102:10:102:15 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:141:21:141:26 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | ActiveRecordInjection.rb:155:59:155:64 | call to params | ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:155:59:155:64 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:168:37:168:41 | query | ActiveRecordInjection.rb:173:5:173:10 | call to params | ActiveRecordInjection.rb:168:37:168:41 | query | This SQL query depends on a $@. | ActiveRecordInjection.rb:173:5:173:10 | call to params | user-provided value |
|
||||
| ActiveRecordInjection.rb:177:43:177:104 | "SELECT * FROM users WHERE id ..." | ActiveRecordInjection.rb:173:5:173:10 | call to params | ActiveRecordInjection.rb:177:43:177:104 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:173:5:173:10 | call to params | user-provided value |
|
||||
@@ -189,4 +196,4 @@ subpaths
|
||||
| PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value |
|
||||
| PgInjection.rb:21:28:21:31 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:21:28:21:31 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value |
|
||||
| PgInjection.rb:32:29:32:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:32:29:32:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value |
|
||||
| PgInjection.rb:44:29:44:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:44:29:44:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value |
|
||||
| PgInjection.rb:44:29:44:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:44:29:44:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value |
|
||||
|
||||
Reference in New Issue
Block a user