Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ A type can be defined by adding ``typeModel`` tuples for that type. Additionally
- The name of an NPM package matches imports of that package. For example, the type ``express`` matches the expression ``require("express")``. If the package name includes dots, it must be surrounded by single quotes, such as in ``'lodash.escape'``.
- The type ``global`` identifies the global object, also known as ``window``. In JavaScript, global variables are properties of the global object, so global variables can be identified using this type. (This type also matches imports of the NPM package named ``global``, which is a package that happens to export the global object.)
- A qualified type name of form ``<package>.<type>`` identifies expressions of type ``<type>`` from ``<package>``. For example, ``mysql.Connection`` identifies expression of type ``Connection`` from the ``mysql`` package. Note that this only works if type annotations are present in the codebase, or if sufficient ``typeModel`` tuples have been provided for that type.
- A string of form ``file:<path>`` identifies expressions that are imported from a file at the given path. The path is relative to the root of the codebase, must use forward slashes as path separator, must include the file extension, and is case-sensitive. For example, ``file:src/utils.js`` identifies expressions such as ``require('./utils')`` inside ``src/``, or ``require('../src/utils')`` inside another top-level folder.

Access paths
------------
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: majorAnalysis
---
* It is now possible for custom models to refer to specific files in the codebase, using a package name of form `file:<path>`. The model should describe the public exports
of that file. This can be used to derive sources and sinks in code that imports the file, but note that sources and sinks will not generally be placed within the file itself.
For example, a source model `['file:lib/service.js', 'Member[getData].ReturnValue', 'remote']` could identify `require('../lib/service').getData()` as a source.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ predicate parseTypeString(string rawType, string package, string qualifiedName)
qualifiedName = ""
}

/** If `type` has the form `file:<path>` gets the path to the file. */
bindingset[type]
overlay[caller]
private string getRawFilePathFromTypeName(string type) {
result = type.regexpCapture("file:(.*)", 1)
}

/**
* Holds if models describing `package` may be relevant for the analysis of this database.
*/
Expand All @@ -76,6 +83,8 @@ predicate isTypeUsed(string type) {
parseTypeString(type, package, _) and
isPackageUsed(package)
)
or
exists(getRawFilePathFromTypeName(type)) // No need to prune repository-specific models
}

/**
Expand Down Expand Up @@ -126,6 +135,41 @@ private API::Node getGlobalNode(string globalName) {
result = any(GlobalApiEntryPoint e | e.getGlobal() = globalName).getANode()
}

/** Holds if `type` is used as a type string in a model, and has the form `file:<filePath>` */
overlay[local]
private predicate relevantRawFilePath(string type, string filePath) {
isRelevantType(type) and
filePath = getRawFilePathFromTypeName(type)
}

/** An API graph entry point for package specifiers of form `file:<path>`. */
overlay[local?]
private class RawFilePathEntryPoint extends API::EntryPoint {
string path;

RawFilePathEntryPoint() {
relevantRawFilePath(_, path) and
this = "RawFilePathEntryPoint:" + path
}

override DataFlow::SourceNode getASource() {
exists(JS::Import imprt |
imprt.getImportedFile().getRelativePath() = path and
result = imprt.getImportedModuleNode()
)
}

/** Gets the name of the path variable. */
string getPath() { result = path }
}

/**
* Gets an API node referring to the given global variable (if relevant).
*/
private API::Node getRawFilePathNode(string rawFilePathNode) {
result = any(RawFilePathEntryPoint e | e.getPath() = rawFilePathNode).getANode()
}

/** Gets a JavaScript-specific interpretation of the `(type, path)` tuple after resolving the first `n` access path tokens. */
bindingset[type, path]
API::Node getExtraNodeFromPath(string type, AccessPath path, int n) {
Expand All @@ -150,6 +194,11 @@ API::Node getExtraNodeFromType(string type) {
// Access instance of a type based on type annotations
result = API::Internal::getANodeOfTypeRaw(package, qualifiedName)
)
or
exists(string filePath |
relevantRawFilePath(type, filePath) and
result = getRawFilePathNode(filePath)
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const foo = 1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as bar from './foo/bar/baz';

function t1() {
sink(bar.customSource()); // NOT OK
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ taintFlow
| guardedRouteHandler.js:10:10:10:28 | res.injectedResData | guardedRouteHandler.js:10:10:10:28 | res.injectedResData |
| guardedRouteHandler.js:16:10:16:28 | req.injectedReqData | guardedRouteHandler.js:16:10:16:28 | req.injectedReqData |
| guardedRouteHandler.js:20:10:20:28 | res.injectedResData | guardedRouteHandler.js:20:10:20:28 | res.injectedResData |
| importFileBasedModel.js:4:10:4:27 | bar.customSource() | importFileBasedModel.js:4:10:4:27 | bar.customSource() |
| paramDecorator.ts:6:54:6:54 | x | paramDecorator.ts:7:10:7:10 | x |
| test.js:5:30:5:37 | source() | test.js:5:8:5:38 | testlib ... urce()) |
| test.js:6:22:6:29 | source() | test.js:6:8:6:30 | preserv ... urce()) |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extensions:
- ['danger-constant', 'Member[danger]', 'test-source']
- ['testlib', 'Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[0].Member[injectedReqData]', 'test-source']
- ['testlib', 'Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[1].Member[injectedResData]', 'test-source']
- ['file:foo/bar/baz.js', 'Member[customSource].ReturnValue', 'test-source']

- addsTo:
pack: codeql/javascript-all
Expand Down
Loading