Skip to content

Commit 4ffe20a

Browse files
authored
Merge pull request github#12189 from erik-krogh/more-export
JS: also consider relative exports when finding library inputs
2 parents f924331 + bec8dc6 commit 4ffe20a

File tree

6 files changed

+26
-16
lines changed

6 files changed

+26
-16
lines changed

javascript/ql/lib/semmle/javascript/NPM.qll

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,20 +198,20 @@ class PackageJson extends JsonObject {
198198
/**
199199
* Gets the main module of this package.
200200
*/
201-
Module getMainModule() {
202-
result = min(Module m, int prio | m.getFile() = resolveMainModule(this, prio) | m order by prio)
203-
}
201+
Module getMainModule() { result = this.getExportedModule(".") }
204202

205203
/**
206204
* Gets the module exported under the given relative path.
207205
*
208206
* The main module is considered exported under the path `"."`.
209207
*/
210208
Module getExportedModule(string relativePath) {
211-
relativePath = "." and
212-
result = this.getMainModule()
213-
or
214-
result.getFile() = MainModulePath::of(this, relativePath).resolve()
209+
result =
210+
min(Module m, int prio |
211+
m.getFile() = resolveMainModule(this, prio, relativePath)
212+
|
213+
m order by prio
214+
)
215215
}
216216

217217
/**

javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ File loadAsFile(Require req, int rootPriority, int priority) {
6262
*/
6363
File loadAsDirectory(Require req, int rootPriority, int priority) {
6464
exists(Folder dir | dir = req.getImportedPath().resolve(rootPriority) |
65-
result = resolveMainModule(dir.(NpmPackage).getPackageJson(), priority) or
65+
result = resolveMainModule(dir.(NpmPackage).getPackageJson(), priority, ".") or
6666
result = tryExtensions(dir, "index", priority - (numberOfExtensions() + 1))
6767
)
6868
}
@@ -132,12 +132,10 @@ private File resolveMainPath(PackageJson pkg, string mainPath, int priority) {
132132
/**
133133
* Gets the main module described by `pkg` with the given `priority`.
134134
*/
135-
File resolveMainModule(PackageJson pkg, int priority) {
136-
exists(int subPriority, string mainPath |
137-
result = resolveMainPath(pkg, mainPath, subPriority) and
138-
if mainPath = "." then subPriority = priority else priority = subPriority + 1000
139-
)
135+
File resolveMainModule(PackageJson pkg, int priority, string exportPath) {
136+
result = resolveMainPath(pkg, exportPath, priority)
140137
or
138+
exportPath = "." and
141139
exists(Folder folder, Folder child |
142140
child = folder or
143141
child = folder.getChildContainer(getASrcFolderName()) or
@@ -149,6 +147,7 @@ File resolveMainModule(PackageJson pkg, int priority) {
149147
)
150148
or
151149
// if there is no main module, then we look for files that are explicitly included in the published package.
150+
exportPath = "." and
152151
exists(PathExpr file |
153152
// `FilesPath` only exists if there is no main module for a given package.
154153
file = FilesPath::of(pkg) and priority = 100 // fixing the priority, because there might be multiple files in the package.

javascript/ql/lib/semmle/javascript/PackageExports.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ private DataFlow::Node getAValueExportedByPackage() {
133133
DataFlow::globalVarRef("define").getACall().getAnArgument() = factory.getALocalUse() and
134134
func.getFile() =
135135
min(int j, File f |
136-
f = NodeModule::resolveMainModule(any(PackageJson pack | exists(pack.getPackageName())), j)
136+
f =
137+
NodeModule::resolveMainModule(any(PackageJson pack | exists(pack.getPackageName())), j,
138+
".")
137139
|
138140
f order by j
139141
)

javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/UnsafeHtmlConstruction.expected

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ nodes
1212
| lib2/index.ts:1:28:1:28 | s |
1313
| lib2/index.ts:2:29:2:29 | s |
1414
| lib2/index.ts:2:29:2:29 | s |
15+
| lib2/src/MyNode.ts:1:28:1:28 | s |
16+
| lib2/src/MyNode.ts:1:28:1:28 | s |
17+
| lib2/src/MyNode.ts:2:29:2:29 | s |
18+
| lib2/src/MyNode.ts:2:29:2:29 | s |
1519
| lib/src/MyNode.ts:1:28:1:28 | s |
1620
| lib/src/MyNode.ts:1:28:1:28 | s |
1721
| lib/src/MyNode.ts:2:29:2:29 | s |
@@ -108,6 +112,10 @@ edges
108112
| lib2/index.ts:1:28:1:28 | s | lib2/index.ts:2:29:2:29 | s |
109113
| lib2/index.ts:1:28:1:28 | s | lib2/index.ts:2:29:2:29 | s |
110114
| lib2/index.ts:1:28:1:28 | s | lib2/index.ts:2:29:2:29 | s |
115+
| lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s |
116+
| lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s |
117+
| lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s |
118+
| lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s |
111119
| lib/src/MyNode.ts:1:28:1:28 | s | lib/src/MyNode.ts:2:29:2:29 | s |
112120
| lib/src/MyNode.ts:1:28:1:28 | s | lib/src/MyNode.ts:2:29:2:29 | s |
113121
| lib/src/MyNode.ts:1:28:1:28 | s | lib/src/MyNode.ts:2:29:2:29 | s |
@@ -200,6 +208,7 @@ edges
200208
| jquery-plugin.js:12:31:12:41 | options.foo | jquery-plugin.js:11:34:11:40 | options | jquery-plugin.js:12:31:12:41 | options.foo | This HTML construction which depends on $@ might later allow $@. | jquery-plugin.js:11:34:11:40 | options | library input | jquery-plugin.js:12:20:12:53 | "<span> ... /span>" | cross-site scripting |
201209
| jquery-plugin.js:14:31:14:35 | stuff | jquery-plugin.js:11:27:11:31 | stuff | jquery-plugin.js:14:31:14:35 | stuff | This HTML construction which depends on $@ might later allow $@. | jquery-plugin.js:11:27:11:31 | stuff | library input | jquery-plugin.js:14:20:14:47 | "<span> ... /span>" | cross-site scripting |
202210
| lib2/index.ts:2:29:2:29 | s | lib2/index.ts:1:28:1:28 | s | lib2/index.ts:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | lib2/index.ts:1:28:1:28 | s | library input | lib2/index.ts:3:49:3:52 | html | cross-site scripting |
211+
| lib2/src/MyNode.ts:2:29:2:29 | s | lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | lib2/src/MyNode.ts:1:28:1:28 | s | library input | lib2/src/MyNode.ts:3:49:3:52 | html | cross-site scripting |
203212
| lib/src/MyNode.ts:2:29:2:29 | s | lib/src/MyNode.ts:1:28:1:28 | s | lib/src/MyNode.ts:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | lib/src/MyNode.ts:1:28:1:28 | s | library input | lib/src/MyNode.ts:3:49:3:52 | html | cross-site scripting |
204213
| main.js:2:29:2:29 | s | main.js:1:55:1:55 | s | main.js:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | main.js:1:55:1:55 | s | library input | main.js:3:49:3:52 | html | cross-site scripting |
205214
| main.js:7:49:7:49 | s | main.js:6:49:6:49 | s | main.js:7:49:7:49 | s | This XML parsing which depends on $@ might later allow $@. | main.js:6:49:6:49 | s | library input | main.js:8:48:8:66 | doc.documentElement | cross-site scripting |

javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "my-unsafe-library",
3-
"main": "./foobar.js",
3+
"main": "./index.ts",
44
"exports": {
55
"./MyNode": {
66
"require": "./lib/MyNode.cjs",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export function trivialXss(s: string) {
2-
const html = "<span>" + s + "</span>"; // OK - this file is not recognized as a main file.
2+
const html = "<span>" + s + "</span>"; // NOT OK - this file is not recognized as a main file.
33
document.querySelector("#html").innerHTML = html;
44
}

0 commit comments

Comments
 (0)