mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Merge pull request #14216 from hmac/hmac-graphql-enum
Ruby: Restrict GraphQL remote flow sources
This commit is contained in:
4
ruby/ql/lib/change-notes/2023-09-18-graphql-sources.md
Normal file
4
ruby/ql/lib/change-notes/2023-09-18-graphql-sources.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* GraphQL enums are no longer considered remote flow sources.
|
||||
@@ -253,6 +253,46 @@ class GraphqlFieldDefinitionMethodCall extends GraphqlSchemaObjectClassMethodCal
|
||||
|
||||
/** Gets the name of this GraphQL field. */
|
||||
string getFieldName() { result = this.getArgument(0).getConstantValue().getStringlikeValue() }
|
||||
|
||||
/**
|
||||
* Gets the type of this field.
|
||||
*/
|
||||
GraphqlType getFieldType() { result = this.getArgument(1) }
|
||||
|
||||
/**
|
||||
* Gets an argument call inside this field definition.
|
||||
*/
|
||||
GraphqlFieldArgumentDefinitionMethodCall getAnArgumentCall() { result = this.getArgumentCall(_) }
|
||||
|
||||
/**
|
||||
* Gets the argument call for `name` inside this field definition.
|
||||
*/
|
||||
GraphqlFieldArgumentDefinitionMethodCall getArgumentCall(string name) {
|
||||
result.getEnclosingCallable() = this.getBlock() and result.getArgumentName() = name
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `argument` in a GraphQL InputObject class.
|
||||
*/
|
||||
class GraphqlInputObjectArgumentDefinitionCall extends DataFlow::CallNode {
|
||||
GraphqlInputObjectArgumentDefinitionCall() {
|
||||
this =
|
||||
graphQlSchema()
|
||||
.getMember("InputObject")
|
||||
.getADescendentModule()
|
||||
.getAnOwnModuleSelf()
|
||||
.getAMethodCall("argument")
|
||||
}
|
||||
|
||||
/** Gets the name of the argument (i.e. the first argument to this `argument` method call) */
|
||||
string getArgumentName() { result = this.getArgument(0).getConstantValue().getStringlikeValue() }
|
||||
|
||||
/** Gets the type of this argument */
|
||||
GraphqlType getArgumentType() { result = this.getArgument(1).asExpr().getExpr() }
|
||||
|
||||
/** Gets the class representing the receiver of this method. */
|
||||
ClassDeclaration getReceiverClass() { result = this.asExpr().getExpr().getEnclosingModule() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,6 +329,64 @@ private class GraphqlFieldArgumentDefinitionMethodCall extends GraphqlSchemaObje
|
||||
|
||||
/** Gets the name of the argument (i.e. the first argument to this `argument` method call) */
|
||||
string getArgumentName() { result = this.getArgument(0).getConstantValue().getStringlikeValue() }
|
||||
|
||||
/** Gets the type of this argument */
|
||||
GraphqlType getArgumentType() { result = this.getArgument(1) }
|
||||
|
||||
/**
|
||||
* Gets the element type of this argument, if it is an array.
|
||||
* For example if the argument type is `[String]`, this predicate yields `String`.
|
||||
*/
|
||||
GraphqlType getArgumentElementType() {
|
||||
result =
|
||||
any(ArrayLiteral lit | lit = this.getArgument(1) and lit.getNumberOfElements() = 1)
|
||||
.getElement(0)
|
||||
}
|
||||
}
|
||||
|
||||
private class GraphqlType extends ConstantAccess {
|
||||
/**
|
||||
* Gets the module corresponding to this type, if it exists.
|
||||
*/
|
||||
Module getModule() { result.getAnImmediateReference() = this }
|
||||
|
||||
/**
|
||||
* Gets the type of a field/argument of this type, if it is an object type.
|
||||
*/
|
||||
GraphqlType getAFieldOrArgument() { result = this.getFieldOrArgument(_) }
|
||||
|
||||
/**
|
||||
* Gets the type of the `name` field/argument of this type, if it exists.
|
||||
*/
|
||||
GraphqlType getFieldOrArgument(string name) {
|
||||
result =
|
||||
any(GraphqlFieldDefinitionMethodCall field |
|
||||
field.getFieldName() = name and
|
||||
this.getModule().getADeclaration() = field.getReceiverClass()
|
||||
).getFieldType() or
|
||||
result =
|
||||
any(GraphqlInputObjectArgumentDefinitionCall arg |
|
||||
arg.getArgumentName() = name and this.getModule().getADeclaration() = arg.getReceiverClass()
|
||||
).getArgumentType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type is an enum.
|
||||
*/
|
||||
predicate isEnum() {
|
||||
API::getTopLevelMember("GraphQL")
|
||||
.getMember("Schema")
|
||||
.getMember("Enum")
|
||||
.getADescendentModule()
|
||||
.getAnImmediateReference()
|
||||
.asExpr()
|
||||
.getExpr() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type is scalar - i.e. it is neither an object or an enum.
|
||||
*/
|
||||
predicate isScalar() { not exists(this.getAFieldOrArgument()) and not this.isEnum() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,29 +448,26 @@ class GraphqlFieldResolutionMethod extends Method, Http::Server::RequestHandler:
|
||||
|
||||
/** Gets the method call which is the definition of the field corresponding to this resolver method. */
|
||||
GraphqlFieldDefinitionMethodCall getDefinition() {
|
||||
result
|
||||
.getKeywordArgument("resolver_method")
|
||||
.getConstantValue()
|
||||
.isStringlikeValue(this.getName())
|
||||
or
|
||||
not exists(result.getKeywordArgument("resolver_method").(SymbolLiteral)) and
|
||||
result.getFieldName() = this.getName()
|
||||
result.getEnclosingModule() = this.getEnclosingModule() and
|
||||
(
|
||||
result
|
||||
.getKeywordArgument("resolver_method")
|
||||
.getConstantValue()
|
||||
.isStringlikeValue(this.getName())
|
||||
or
|
||||
not exists(result.getKeywordArgument("resolver_method").(SymbolLiteral)) and
|
||||
result.getFieldName() = this.getName()
|
||||
)
|
||||
}
|
||||
|
||||
// check for a named argument the same name as a defined argument for this field
|
||||
override Parameter getARoutedParameter() {
|
||||
result = this.getAParameter() and
|
||||
exists(GraphqlFieldArgumentDefinitionMethodCall argDefn |
|
||||
argDefn.getEnclosingCallable() = this.getDefinition().getBlock() and
|
||||
(
|
||||
result.(KeywordParameter).hasName(argDefn.getArgumentName())
|
||||
or
|
||||
// TODO this will cause false positives because now *anything* in the **args
|
||||
// param will be flagged as RoutedParameter/RemoteFlowSource, but really
|
||||
// only the hash keys corresponding to the defined arguments are user input
|
||||
// others could be things defined in the `:extras` keyword argument to the `argument`
|
||||
result instanceof HashSplatParameter // often you see `def field(**args)`
|
||||
)
|
||||
argDefn = this.getDefinition().getAnArgumentCall() and
|
||||
[argDefn.getArgumentType(), argDefn.getArgumentElementType()].isScalar()
|
||||
|
|
||||
result.(KeywordParameter).hasName(argDefn.getArgumentName())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -383,3 +478,80 @@ class GraphqlFieldResolutionMethod extends Method, Http::Server::RequestHandler:
|
||||
/** Gets the class containing this method. */
|
||||
GraphqlSchemaObjectClass getGraphqlClass() { result = schemaObjectClass }
|
||||
}
|
||||
|
||||
private DataFlow::CallNode hashParameterAccess(
|
||||
GraphqlFieldResolutionMethod method, HashSplatParameter param, GraphqlType type
|
||||
) {
|
||||
exists(
|
||||
DataFlow::LocalSourceNode paramNode, GraphqlFieldArgumentDefinitionMethodCall def, string key
|
||||
|
|
||||
param = method.getAParameter() and
|
||||
paramNode.(DataFlow::ParameterNode).getParameter() = param and
|
||||
def = method.getDefinition().getAnArgumentCall() and
|
||||
(
|
||||
// Direct access to the params hash
|
||||
[def.getArgumentType(), def.getArgumentElementType()] = type and
|
||||
def.getArgumentName() = key and
|
||||
paramNode.flowsTo(hashAccess(result, key))
|
||||
or
|
||||
// Nested access
|
||||
exists(GraphqlType type2 |
|
||||
hashParameterAccess(method, param, type2)
|
||||
.(DataFlow::LocalSourceNode)
|
||||
.flowsTo(hashAccess(result, key)) and
|
||||
type2.getFieldOrArgument(key) = type
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private DataFlow::Node parameterAccess(
|
||||
GraphqlFieldResolutionMethod method, DataFlow::LocalSourceNode param, GraphqlType type
|
||||
) {
|
||||
param = getAGraphqlParameter(method, type) and
|
||||
result = param
|
||||
or
|
||||
exists(string key, GraphqlType type2 |
|
||||
param = parameterAccess(method, _, type2) and
|
||||
param.flowsTo(hashAccess(result, key)) and
|
||||
type2.getFieldOrArgument(key) = type
|
||||
)
|
||||
}
|
||||
|
||||
private DataFlow::ParameterNode getAGraphqlParameter(
|
||||
GraphqlFieldResolutionMethod method, GraphqlType type
|
||||
) {
|
||||
result.getCallable() = method and
|
||||
(
|
||||
result.getParameter() instanceof KeywordParameter and
|
||||
exists(GraphqlFieldArgumentDefinitionMethodCall c |
|
||||
c = method.getDefinition().getArgumentCall(result.getName())
|
||||
|
|
||||
type = [c.getArgumentType(), c.getArgumentElementType()]
|
||||
)
|
||||
or
|
||||
result.getParameter() instanceof SimpleParameter and
|
||||
type = method.getDefinition().getFieldType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the receiver of the hash access `access` with key `key`.
|
||||
* For example, in `h["foo"]` the receiver is `h`, the key is "foo"
|
||||
* and `access` is the dataflow node for the whole expression.
|
||||
*/
|
||||
private DataFlow::Node hashAccess(DataFlow::CallNode access, string key) {
|
||||
access.asExpr() instanceof ExprNodes::ElementReferenceCfgNode and
|
||||
access.getArgument(0).getConstantValue().isStringlikeValue(key) and
|
||||
access.getReceiver() = result
|
||||
}
|
||||
|
||||
private class GraphqlParameterAccess extends RemoteFlowSource::Range {
|
||||
GraphqlParameterAccess() {
|
||||
exists(GraphqlType type | type.isScalar() |
|
||||
this = hashParameterAccess(_, _, type) or this = parameterAccess(_, _, type)
|
||||
)
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "GraphQL" }
|
||||
}
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
graphqlSchemaObjectClass
|
||||
| app/graphql/types/base_object.rb:2:3:4:5 | BaseObject |
|
||||
| app/graphql/types/mutation_type.rb:2:3:4:5 | MutationType |
|
||||
| app/graphql/types/query_type.rb:2:3:45:5 | QueryType |
|
||||
| app/graphql/types/post.rb:1:1:6:5 | Post |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType |
|
||||
graphqlSchemaObjectFieldDefinition
|
||||
| app/graphql/types/mutation_type.rb:2:3:4:5 | MutationType | app/graphql/types/mutation_type.rb:3:5:3:44 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:45:5 | QueryType | app/graphql/types/query_type.rb:3:5:5:40 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:45:5 | QueryType | app/graphql/types/query_type.rb:7:5:9:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:45:5 | QueryType | app/graphql/types/query_type.rb:15:5:17:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:45:5 | QueryType | app/graphql/types/query_type.rb:24:5:26:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:45:5 | QueryType | app/graphql/types/query_type.rb:32:5:35:7 | call to field |
|
||||
| app/graphql/types/post.rb:1:1:6:5 | Post | app/graphql/types/post.rb:2:5:2:24 | call to field |
|
||||
| app/graphql/types/post.rb:1:1:6:5 | Post | app/graphql/types/post.rb:3:5:3:36 | call to field |
|
||||
| app/graphql/types/post.rb:1:1:6:5 | Post | app/graphql/types/post.rb:4:5:4:60 | call to field |
|
||||
| app/graphql/types/post.rb:1:1:6:5 | Post | app/graphql/types/post.rb:5:5:5:51 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:3:5:5:40 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:7:5:9:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:15:5:17:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:24:5:26:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:32:5:35:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:46:5:49:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:55:5:57:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:65:5:67:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:2:3:85:5 | QueryType | app/graphql/types/query_type.rb:72:5:76:7 | call to field |
|
||||
graphqlResolveMethod
|
||||
| app/graphql/mutations/dummy.rb:9:5:12:7 | resolve |
|
||||
| app/graphql/resolvers/dummy_resolver.rb:10:5:13:7 | resolve |
|
||||
@@ -23,24 +32,56 @@ graphqlLoadMethodRoutedParameter
|
||||
| app/graphql/resolvers/dummy_resolver.rb:6:5:8:7 | load_something | app/graphql/resolvers/dummy_resolver.rb:6:24:6:25 | id |
|
||||
graphqlFieldDefinitionMethodCall
|
||||
| app/graphql/types/mutation_type.rb:3:5:3:44 | call to field |
|
||||
| app/graphql/types/post.rb:2:5:2:24 | call to field |
|
||||
| app/graphql/types/post.rb:3:5:3:36 | call to field |
|
||||
| app/graphql/types/post.rb:4:5:4:60 | call to field |
|
||||
| app/graphql/types/post.rb:5:5:5:51 | call to field |
|
||||
| app/graphql/types/query_type.rb:3:5:5:40 | call to field |
|
||||
| app/graphql/types/query_type.rb:7:5:9:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:15:5:17:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:24:5:26:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:32:5:35:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:46:5:49:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:55:5:57:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:65:5:67:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:72:5:76:7 | call to field |
|
||||
graphqlFieldResolutionMethod
|
||||
| app/graphql/types/query_type.rb:10:5:13:7 | with_arg |
|
||||
| app/graphql/types/query_type.rb:18:5:22:7 | custom_method |
|
||||
| app/graphql/types/query_type.rb:27:5:30:7 | with_splat |
|
||||
| app/graphql/types/query_type.rb:36:5:40:7 | with_splat_and_named_arg |
|
||||
| app/graphql/types/query_type.rb:50:5:53:7 | with_enum |
|
||||
| app/graphql/types/query_type.rb:58:5:63:7 | with_nested_enum |
|
||||
| app/graphql/types/query_type.rb:68:5:70:7 | with_array |
|
||||
| app/graphql/types/query_type.rb:77:5:84:7 | with_named_params |
|
||||
graphqlFieldResolutionRoutedParameter
|
||||
| app/graphql/types/query_type.rb:10:5:13:7 | with_arg | app/graphql/types/query_type.rb:10:18:10:23 | number |
|
||||
| app/graphql/types/query_type.rb:18:5:22:7 | custom_method | app/graphql/types/query_type.rb:18:23:18:33 | blah_number |
|
||||
| app/graphql/types/query_type.rb:27:5:30:7 | with_splat | app/graphql/types/query_type.rb:27:20:27:25 | **args |
|
||||
| app/graphql/types/query_type.rb:36:5:40:7 | with_splat_and_named_arg | app/graphql/types/query_type.rb:36:34:36:37 | arg1 |
|
||||
| app/graphql/types/query_type.rb:36:5:40:7 | with_splat_and_named_arg | app/graphql/types/query_type.rb:36:41:36:46 | **rest |
|
||||
| app/graphql/types/query_type.rb:68:5:70:7 | with_array | app/graphql/types/query_type.rb:68:20:68:23 | list |
|
||||
| app/graphql/types/query_type.rb:77:5:84:7 | with_named_params | app/graphql/types/query_type.rb:77:27:77:30 | arg1 |
|
||||
graphqlFieldResolutionDefinition
|
||||
| app/graphql/types/query_type.rb:10:5:13:7 | with_arg | app/graphql/types/query_type.rb:7:5:9:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:18:5:22:7 | custom_method | app/graphql/types/query_type.rb:15:5:17:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:27:5:30:7 | with_splat | app/graphql/types/query_type.rb:24:5:26:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:36:5:40:7 | with_splat_and_named_arg | app/graphql/types/query_type.rb:32:5:35:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:50:5:53:7 | with_enum | app/graphql/types/query_type.rb:46:5:49:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:58:5:63:7 | with_nested_enum | app/graphql/types/query_type.rb:55:5:57:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:68:5:70:7 | with_array | app/graphql/types/query_type.rb:65:5:67:7 | call to field |
|
||||
| app/graphql/types/query_type.rb:77:5:84:7 | with_named_params | app/graphql/types/query_type.rb:72:5:76:7 | call to field |
|
||||
graphqlRemoteFlowSources
|
||||
| app/graphql/mutations/dummy.rb:5:24:5:25 | id |
|
||||
| app/graphql/mutations/dummy.rb:9:17:9:25 | something |
|
||||
| app/graphql/resolvers/dummy_resolver.rb:6:24:6:25 | id |
|
||||
| app/graphql/resolvers/dummy_resolver.rb:10:17:10:25 | something |
|
||||
| app/graphql/types/query_type.rb:10:18:10:23 | number |
|
||||
| app/graphql/types/query_type.rb:18:23:18:33 | blah_number |
|
||||
| app/graphql/types/query_type.rb:28:22:28:37 | ...[...] |
|
||||
| app/graphql/types/query_type.rb:29:7:29:22 | ...[...] |
|
||||
| app/graphql/types/query_type.rb:36:34:36:37 | arg1 |
|
||||
| app/graphql/types/query_type.rb:38:22:38:32 | ...[...] |
|
||||
| app/graphql/types/query_type.rb:52:22:52:32 | ...[...] |
|
||||
| app/graphql/types/query_type.rb:60:22:60:41 | ...[...] |
|
||||
| app/graphql/types/query_type.rb:68:20:68:23 | list |
|
||||
| app/graphql/types/query_type.rb:77:27:77:30 | arg1 |
|
||||
| app/graphql/types/query_type.rb:80:22:80:33 | ...[...] |
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
private import codeql.ruby.frameworks.GraphQL
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.dataflow.RemoteFlowSources
|
||||
|
||||
query predicate graphqlSchemaObjectClass(GraphqlSchemaObjectClass cls) { any() }
|
||||
|
||||
@@ -34,3 +35,5 @@ query predicate graphqlFieldResolutionDefinition(
|
||||
) {
|
||||
meth.getDefinition() = def
|
||||
}
|
||||
|
||||
query predicate graphqlRemoteFlowSources(RemoteFlowSource src) { any() }
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
class Types::BaseEnum < GraphQL::Schema::Enum
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
module Types
|
||||
class Direction < Types::BaseEnum
|
||||
value "asc", "Ascending order", value: "asc"
|
||||
value "desc", "Descending order", value: "desc"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
module Types
|
||||
class MediaCategory < Types::BaseEnum
|
||||
value "AUDIO", "An audio file, such as music or spoken word"
|
||||
value "IMAGE", "A still image, such as a photo or graphic"
|
||||
value "TEXT", "Written words"
|
||||
value "VIDEO", "Motion picture, may have audio"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
class Types::Post < GraphQL::Schema::Object
|
||||
field :title, String
|
||||
field :body, String, null: false
|
||||
field :media_category, Types::MediaCategory, null: false
|
||||
field :direction, Types::Direction, null: false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
module Types
|
||||
class PostOrder < Types::BaseInputObject
|
||||
argument :direction, Types::Direction, "The ordering direction", required: true
|
||||
end
|
||||
end
|
||||
@@ -42,5 +42,45 @@ module Types
|
||||
def foo(arg)
|
||||
system("echo #{arg}")
|
||||
end
|
||||
|
||||
field :with_enum, String, null: false, description: "A field with an enum argument" do
|
||||
argument :enum, Types::MediaCategory, "An enum", required: true
|
||||
argument :arg2, String, "Another arg", required: true
|
||||
end
|
||||
def with_enum(**args)
|
||||
system("echo #{args[:enum]}")
|
||||
system("echo #{args[:arg2]}")
|
||||
end
|
||||
|
||||
field :with_nested_enum, String, null: false, description: "A field with a nested enum argument" do
|
||||
argument :inner, Types::Post, "Post", required: true
|
||||
end
|
||||
def with_nested_enum(**args)
|
||||
system("echo #{args[:inner]}")
|
||||
system("echo #{args[:inner][:title]}")
|
||||
system("echo #{args[:inner][:media_category]}")
|
||||
system("echo #{args[:inner][:direction]}")
|
||||
end
|
||||
|
||||
field :with_array, String do
|
||||
argument :list, [String], "Names"
|
||||
end
|
||||
def with_array(list:)
|
||||
system("echo #{list[0]}")
|
||||
end
|
||||
|
||||
field :with_named_params, String do
|
||||
argument :arg1, String, "Arg 1"
|
||||
argument :arg2, Types::Post, "Arg 2"
|
||||
argument :arg3, Types::MediaCategory, "Arg 3"
|
||||
end
|
||||
def with_named_params(arg1:, arg2:, **args)
|
||||
system("echo #{arg1}")
|
||||
system("echo #{arg2}")
|
||||
system("echo #{arg2[:title]}")
|
||||
system("echo #{arg2[:media_category]}")
|
||||
system("echo #{args[:arg3]}")
|
||||
system("echo #{args[:not_an_arg]}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,8 +17,6 @@ edges
|
||||
| CommandInjection.rb:54:13:54:24 | ...[...] | CommandInjection.rb:54:7:54:9 | cmd |
|
||||
| CommandInjection.rb:73:18:73:23 | number | CommandInjection.rb:74:14:74:29 | "echo #{...}" |
|
||||
| CommandInjection.rb:81:23:81:33 | blah_number | CommandInjection.rb:82:14:82:34 | "echo #{...}" |
|
||||
| CommandInjection.rb:90:20:90:25 | **args | CommandInjection.rb:91:22:91:25 | args |
|
||||
| CommandInjection.rb:91:22:91:25 | args | CommandInjection.rb:91:22:91:37 | ...[...] |
|
||||
| CommandInjection.rb:91:22:91:37 | ...[...] | CommandInjection.rb:91:14:91:39 | "echo #{...}" |
|
||||
| CommandInjection.rb:103:9:103:12 | file | CommandInjection.rb:104:16:104:28 | "cat #{...}" |
|
||||
| CommandInjection.rb:103:16:103:21 | call to params | CommandInjection.rb:103:16:103:28 | ...[...] |
|
||||
@@ -47,9 +45,7 @@ nodes
|
||||
| CommandInjection.rb:74:14:74:29 | "echo #{...}" | semmle.label | "echo #{...}" |
|
||||
| CommandInjection.rb:81:23:81:33 | blah_number | semmle.label | blah_number |
|
||||
| CommandInjection.rb:82:14:82:34 | "echo #{...}" | semmle.label | "echo #{...}" |
|
||||
| CommandInjection.rb:90:20:90:25 | **args | semmle.label | **args |
|
||||
| CommandInjection.rb:91:14:91:39 | "echo #{...}" | semmle.label | "echo #{...}" |
|
||||
| CommandInjection.rb:91:22:91:25 | args | semmle.label | args |
|
||||
| CommandInjection.rb:91:22:91:37 | ...[...] | semmle.label | ...[...] |
|
||||
| CommandInjection.rb:103:9:103:12 | file | semmle.label | file |
|
||||
| CommandInjection.rb:103:16:103:21 | call to params | semmle.label | call to params |
|
||||
@@ -69,5 +65,5 @@ subpaths
|
||||
| CommandInjection.rb:59:14:59:16 | cmd | CommandInjection.rb:54:13:54:18 | call to params | CommandInjection.rb:59:14:59:16 | cmd | This command depends on a $@. | CommandInjection.rb:54:13:54:18 | call to params | user-provided value |
|
||||
| CommandInjection.rb:74:14:74:29 | "echo #{...}" | CommandInjection.rb:73:18:73:23 | number | CommandInjection.rb:74:14:74:29 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:73:18:73:23 | number | user-provided value |
|
||||
| CommandInjection.rb:82:14:82:34 | "echo #{...}" | CommandInjection.rb:81:23:81:33 | blah_number | CommandInjection.rb:82:14:82:34 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:81:23:81:33 | blah_number | user-provided value |
|
||||
| CommandInjection.rb:91:14:91:39 | "echo #{...}" | CommandInjection.rb:90:20:90:25 | **args | CommandInjection.rb:91:14:91:39 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:90:20:90:25 | **args | user-provided value |
|
||||
| CommandInjection.rb:91:14:91:39 | "echo #{...}" | CommandInjection.rb:91:22:91:37 | ...[...] | CommandInjection.rb:91:14:91:39 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:91:22:91:37 | ...[...] | user-provided value |
|
||||
| CommandInjection.rb:104:16:104:28 | "cat #{...}" | CommandInjection.rb:103:16:103:21 | call to params | CommandInjection.rb:104:16:104:28 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:103:16:103:21 | call to params | user-provided value |
|
||||
|
||||
Reference in New Issue
Block a user