circle-ir 3.112.0 → 3.113.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/config-loader.d.ts.map +1 -1
- package/dist/analysis/config-loader.js +14 -0
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/passes/insecure-cookie-pass.d.ts +2 -0
- package/dist/analysis/passes/insecure-cookie-pass.d.ts.map +1 -1
- package/dist/analysis/passes/insecure-cookie-pass.js +107 -5
- package/dist/analysis/passes/insecure-cookie-pass.js.map +1 -1
- package/dist/browser/circle-ir.js +82 -3
- package/dist/core/circle-ir-core.cjs +14 -0
- package/dist/core/circle-ir-core.js +14 -0
- package/package.json +1 -1
|
@@ -48,6 +48,8 @@ export declare class InsecureCookiePass implements AnalysisPass<InsecureCookieRe
|
|
|
48
48
|
private detectJs;
|
|
49
49
|
private detectPython;
|
|
50
50
|
private detectJavaCookieCtor;
|
|
51
|
+
private detectGo;
|
|
52
|
+
private detectRustSetCookieFormat;
|
|
51
53
|
private emit;
|
|
52
54
|
}
|
|
53
55
|
//# sourceMappingURL=insecure-cookie-pass.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insecure-cookie-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/insecure-cookie-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"insecure-cookie-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/insecure-cookie-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAsC9E,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,KAAK,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,OAAO,CAAC;QACvB,eAAe,EAAE,OAAO,CAAC;QACzB,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC,CAAC;CACJ;AAED,qBAAa,kBAAmB,YAAW,YAAY,CAAC,oBAAoB,CAAC;IAC3E,QAAQ,CAAC,IAAI,qBAAqB;IAClC,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,oBAAoB;IAkD3C,OAAO,CAAC,QAAQ;IA2BhB,OAAO,CAAC,YAAY;IAuBpB,OAAO,CAAC,oBAAoB;IAqC5B,OAAO,CAAC,QAAQ;IA8BhB,OAAO,CAAC,yBAAyB;IA0BjC,OAAO,CAAC,IAAI;CA4Db"}
|
|
@@ -46,6 +46,20 @@ const PY_HTTPONLY_TRUE_RE = /\bhttponly\s*=\s*True\b/i;
|
|
|
46
46
|
// ---------- Java ----------
|
|
47
47
|
const JAVA_SET_SECURE_TRUE_RE = /\.setSecure\s*\(\s*true\s*\)/;
|
|
48
48
|
const JAVA_SET_HTTPONLY_TRUE_RE = /\.setHttpOnly\s*\(\s*true\s*\)/;
|
|
49
|
+
// ---------- Go ----------
|
|
50
|
+
// `http.SetCookie(w, &http.Cookie{..., Secure: true, HttpOnly: true})` —
|
|
51
|
+
// the struct literal text is in the second argument's expression. Sprint 56 #182 Slice B.
|
|
52
|
+
const GO_SECURE_TRUE_RE = /\bSecure\s*:\s*true\b/;
|
|
53
|
+
const GO_HTTPONLY_TRUE_RE = /\bHttpOnly\s*:\s*true\b/;
|
|
54
|
+
// ---------- Rust ----------
|
|
55
|
+
// `format!("Set-Cookie: sid={}; Path=/; Secure; HttpOnly", ...)` /
|
|
56
|
+
// `write!(buf, "Set-Cookie: ...", ...)` / `writeln!(...)`. The Rust macro
|
|
57
|
+
// extractor surfaces method_name='format!'/'write!'/'writeln!' but does not
|
|
58
|
+
// populate `arguments`, so we text-scan the file source for the macro
|
|
59
|
+
// invocation containing a `Set-Cookie:` header literal and verify that the
|
|
60
|
+
// same invocation also contains `Secure` and `HttpOnly` tokens. Sprint 56 #182 Slice C.
|
|
61
|
+
// Multi-line matches are supported via the `s` flag (dotall).
|
|
62
|
+
const RUST_SET_COOKIE_MACRO_RE = /(format!|write!|writeln!)\s*\(([^()]*Set-Cookie[^()]*)\)/gis;
|
|
49
63
|
export class InsecureCookiePass {
|
|
50
64
|
name = 'insecure-cookie';
|
|
51
65
|
category = 'security';
|
|
@@ -85,6 +99,22 @@ export class InsecureCookiePass {
|
|
|
85
99
|
this.emit(ctx, file, det, 'java');
|
|
86
100
|
}
|
|
87
101
|
}
|
|
102
|
+
else if (language === 'go') {
|
|
103
|
+
for (const call of graph.ir.calls) {
|
|
104
|
+
const det = this.detectGo(call);
|
|
105
|
+
if (!det)
|
|
106
|
+
continue;
|
|
107
|
+
insecureCookies.push(det);
|
|
108
|
+
this.emit(ctx, file, det, 'go');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else if (language === 'rust') {
|
|
112
|
+
const dets = this.detectRustSetCookieFormat(code);
|
|
113
|
+
for (const det of dets) {
|
|
114
|
+
insecureCookies.push(det);
|
|
115
|
+
this.emit(ctx, file, det, 'rust');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
88
118
|
return { insecureCookies };
|
|
89
119
|
}
|
|
90
120
|
// ---------------- JS / TS ----------------
|
|
@@ -167,17 +197,89 @@ export class InsecureCookiePass {
|
|
|
167
197
|
optionsPresent: false,
|
|
168
198
|
};
|
|
169
199
|
}
|
|
200
|
+
// ---------------- Go ----------------
|
|
201
|
+
detectGo(call) {
|
|
202
|
+
// `http.SetCookie(w, &http.Cookie{...})` — Go extractor surfaces
|
|
203
|
+
// method_name='SetCookie', receiver='http'. The struct-literal text
|
|
204
|
+
// for the cookie is in the second argument's expression.
|
|
205
|
+
if (call.method_name !== 'SetCookie')
|
|
206
|
+
return null;
|
|
207
|
+
if ((call.receiver ?? '') !== 'http')
|
|
208
|
+
return null;
|
|
209
|
+
if (call.arguments.length < 2)
|
|
210
|
+
return null;
|
|
211
|
+
const cookieArg = call.arguments.find((a) => a.position === 1);
|
|
212
|
+
const cookieExpr = (cookieArg?.expression ?? '').trim();
|
|
213
|
+
// Variable-form `http.SetCookie(w, cookie)` (where `cookie` is a previously
|
|
214
|
+
// built variable) cannot be inspected at the call site. Skip unless the
|
|
215
|
+
// expression looks like a struct literal (contains `{` and `}`). Mirrors
|
|
216
|
+
// the existing JS spread-options known limitation.
|
|
217
|
+
if (!cookieExpr.includes('{') || !cookieExpr.includes('}'))
|
|
218
|
+
return null;
|
|
219
|
+
const missingSecure = !GO_SECURE_TRUE_RE.test(cookieExpr);
|
|
220
|
+
const missingHttpOnly = !GO_HTTPONLY_TRUE_RE.test(cookieExpr);
|
|
221
|
+
if (!missingSecure && !missingHttpOnly)
|
|
222
|
+
return null;
|
|
223
|
+
return {
|
|
224
|
+
line: call.location.line,
|
|
225
|
+
receiver: 'http.SetCookie',
|
|
226
|
+
missingSecure,
|
|
227
|
+
missingHttpOnly,
|
|
228
|
+
optionsPresent: true,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// ---------------- Rust ----------------
|
|
232
|
+
detectRustSetCookieFormat(code) {
|
|
233
|
+
// Text-based: find `format!(...)` / `write!(...)` / `writeln!(...)` whose
|
|
234
|
+
// body contains a `Set-Cookie:` header literal, then check the same body
|
|
235
|
+
// for `Secure` and `HttpOnly` tokens.
|
|
236
|
+
const out = [];
|
|
237
|
+
const re = new RegExp(RUST_SET_COOKIE_MACRO_RE.source, RUST_SET_COOKIE_MACRO_RE.flags);
|
|
238
|
+
let m;
|
|
239
|
+
while ((m = re.exec(code)) !== null) {
|
|
240
|
+
const macro = m[1] ?? '';
|
|
241
|
+
const body = m[2] ?? '';
|
|
242
|
+
const missingSecure = !/\bSecure\b/.test(body);
|
|
243
|
+
const missingHttpOnly = !/\bHttpOnly\b/.test(body);
|
|
244
|
+
if (!missingSecure && !missingHttpOnly)
|
|
245
|
+
continue;
|
|
246
|
+
// 1-based line number of the macro invocation start.
|
|
247
|
+
const line = code.slice(0, m.index).split('\n').length;
|
|
248
|
+
out.push({
|
|
249
|
+
line,
|
|
250
|
+
receiver: macro,
|
|
251
|
+
missingSecure,
|
|
252
|
+
missingHttpOnly,
|
|
253
|
+
optionsPresent: true,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return out;
|
|
257
|
+
}
|
|
170
258
|
emit(ctx, file, det, flavor) {
|
|
171
259
|
const missing = [];
|
|
172
|
-
if (det.missingSecure)
|
|
173
|
-
missing.push(flavor === 'js' ? '`secure: true`'
|
|
174
|
-
|
|
175
|
-
|
|
260
|
+
if (det.missingSecure) {
|
|
261
|
+
missing.push(flavor === 'js' ? '`secure: true`'
|
|
262
|
+
: flavor === 'python' ? '`secure=True`'
|
|
263
|
+
: flavor === 'java' ? '`setSecure(true)`'
|
|
264
|
+
: flavor === 'go' ? '`Secure: true`'
|
|
265
|
+
: '`Secure` attribute');
|
|
266
|
+
}
|
|
267
|
+
if (det.missingHttpOnly) {
|
|
268
|
+
missing.push(flavor === 'js' ? '`httpOnly: true`'
|
|
269
|
+
: flavor === 'python' ? '`httponly=True`'
|
|
270
|
+
: flavor === 'java' ? '`setHttpOnly(true)`'
|
|
271
|
+
: flavor === 'go' ? '`HttpOnly: true`'
|
|
272
|
+
: '`HttpOnly` attribute');
|
|
273
|
+
}
|
|
176
274
|
const fix = flavor === 'js'
|
|
177
275
|
? 'Pass `{ secure: true, httpOnly: true, sameSite: "lax" }` as the third argument to `res.cookie()`.'
|
|
178
276
|
: flavor === 'python'
|
|
179
277
|
? 'Pass `secure=True, httponly=True, samesite="Lax"` to `response.set_cookie(...)`.'
|
|
180
|
-
:
|
|
278
|
+
: flavor === 'java'
|
|
279
|
+
? 'After constructing the cookie, call `cookie.setSecure(true)` and `cookie.setHttpOnly(true)` before adding it to the response.'
|
|
280
|
+
: flavor === 'go'
|
|
281
|
+
? 'Set `Secure: true` and `HttpOnly: true` on the `http.Cookie` struct literal passed to `http.SetCookie`.'
|
|
282
|
+
: 'Append `; Secure; HttpOnly` to the `Set-Cookie` header string.';
|
|
181
283
|
ctx.addFinding({
|
|
182
284
|
id: `${this.name}-${file}-${det.line}`,
|
|
183
285
|
pass: this.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insecure-cookie-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/insecure-cookie-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAKH,gCAAgC;AAChC,MAAM,yBAAyB,GAAG,IAAI,GAAG,CAAC;IACxC,KAAK,EAAE,UAAU,EAAE,OAAO;CAC3B,CAAC,CAAC;AACH,MAAM,cAAc,GAAK,uBAAuB,CAAC;AACjD,MAAM,gBAAgB,GAAG,0BAA0B,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC;IACtC,UAAU,EAAE,MAAM,EAAE,KAAK;CAC1B,CAAC,CAAC;AACH,MAAM,iBAAiB,GAAK,uBAAuB,CAAC;AACpD,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AAEvD,6BAA6B;AAC7B,MAAM,uBAAuB,GAAK,8BAA8B,CAAC;AACjE,MAAM,yBAAyB,GAAG,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"insecure-cookie-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/insecure-cookie-pass.ts"],"names":[],"mappings":"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"}
|
|
@@ -12140,6 +12140,11 @@ var DEFAULT_SINKS = [
|
|
|
12140
12140
|
{ method: "exec", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
12141
12141
|
{ method: "compile", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
12142
12142
|
{ method: "__import__", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
12143
|
+
// Python dynamic import — `importlib.import_module(taint)` parallels Java's
|
|
12144
|
+
// `Class.forName`. The bare `__import__` entry above also matches the
|
|
12145
|
+
// `importlib.__import__` form because the sink-matcher is class-agnostic
|
|
12146
|
+
// when a classless entry exists. Sprint 56 #183.
|
|
12147
|
+
{ method: "import_module", class: "importlib", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
12143
12148
|
// Python Deserialization — language-scoped so the lowercase `yaml` / `pickle`
|
|
12144
12149
|
// module names don't collide with Java locals named `yaml` (SnakeYAML usage).
|
|
12145
12150
|
{ method: "loads", class: "pickle", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
@@ -12397,6 +12402,15 @@ var DEFAULT_SINKS = [
|
|
|
12397
12402
|
// Standard library logging
|
|
12398
12403
|
{ method: "println!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2] },
|
|
12399
12404
|
{ method: "eprintln!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2] },
|
|
12405
|
+
// log:: namespaced forms — the Rust macro extractor preserves the full
|
|
12406
|
+
// path prefix in `method_name` (`log::info!`), so the bare entries above
|
|
12407
|
+
// only match the imported form `use log::info; info!(...)`. Sprint 56 #182 Slice A.
|
|
12408
|
+
{ method: "log::info!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
12409
|
+
{ method: "log::warn!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
12410
|
+
{ method: "log::error!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
12411
|
+
{ method: "log::debug!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
12412
|
+
{ method: "log::trace!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
12413
|
+
{ method: "log::log!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
12400
12414
|
// Rust sqlx SQL Injection
|
|
12401
12415
|
{ method: "query", class: "sqlx", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
|
12402
12416
|
{ method: "query_as", class: "sqlx", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
|
@@ -31325,6 +31339,9 @@ var PY_SECURE_TRUE_RE = /\bsecure\s*=\s*True\b/;
|
|
|
31325
31339
|
var PY_HTTPONLY_TRUE_RE = /\bhttponly\s*=\s*True\b/i;
|
|
31326
31340
|
var JAVA_SET_SECURE_TRUE_RE = /\.setSecure\s*\(\s*true\s*\)/;
|
|
31327
31341
|
var JAVA_SET_HTTPONLY_TRUE_RE = /\.setHttpOnly\s*\(\s*true\s*\)/;
|
|
31342
|
+
var GO_SECURE_TRUE_RE = /\bSecure\s*:\s*true\b/;
|
|
31343
|
+
var GO_HTTPONLY_TRUE_RE = /\bHttpOnly\s*:\s*true\b/;
|
|
31344
|
+
var RUST_SET_COOKIE_MACRO_RE = /(format!|write!|writeln!)\s*\(([^()]*Set-Cookie[^()]*)\)/gis;
|
|
31328
31345
|
var InsecureCookiePass = class {
|
|
31329
31346
|
name = "insecure-cookie";
|
|
31330
31347
|
category = "security";
|
|
@@ -31355,6 +31372,19 @@ var InsecureCookiePass = class {
|
|
|
31355
31372
|
insecureCookies.push(det);
|
|
31356
31373
|
this.emit(ctx, file, det, "java");
|
|
31357
31374
|
}
|
|
31375
|
+
} else if (language === "go") {
|
|
31376
|
+
for (const call of graph.ir.calls) {
|
|
31377
|
+
const det = this.detectGo(call);
|
|
31378
|
+
if (!det) continue;
|
|
31379
|
+
insecureCookies.push(det);
|
|
31380
|
+
this.emit(ctx, file, det, "go");
|
|
31381
|
+
}
|
|
31382
|
+
} else if (language === "rust") {
|
|
31383
|
+
const dets = this.detectRustSetCookieFormat(code);
|
|
31384
|
+
for (const det of dets) {
|
|
31385
|
+
insecureCookies.push(det);
|
|
31386
|
+
this.emit(ctx, file, det, "rust");
|
|
31387
|
+
}
|
|
31358
31388
|
}
|
|
31359
31389
|
return { insecureCookies };
|
|
31360
31390
|
}
|
|
@@ -31414,11 +31444,60 @@ var InsecureCookiePass = class {
|
|
|
31414
31444
|
optionsPresent: false
|
|
31415
31445
|
};
|
|
31416
31446
|
}
|
|
31447
|
+
// ---------------- Go ----------------
|
|
31448
|
+
detectGo(call) {
|
|
31449
|
+
if (call.method_name !== "SetCookie") return null;
|
|
31450
|
+
if ((call.receiver ?? "") !== "http") return null;
|
|
31451
|
+
if (call.arguments.length < 2) return null;
|
|
31452
|
+
const cookieArg = call.arguments.find((a) => a.position === 1);
|
|
31453
|
+
const cookieExpr = (cookieArg?.expression ?? "").trim();
|
|
31454
|
+
if (!cookieExpr.includes("{") || !cookieExpr.includes("}")) return null;
|
|
31455
|
+
const missingSecure = !GO_SECURE_TRUE_RE.test(cookieExpr);
|
|
31456
|
+
const missingHttpOnly = !GO_HTTPONLY_TRUE_RE.test(cookieExpr);
|
|
31457
|
+
if (!missingSecure && !missingHttpOnly) return null;
|
|
31458
|
+
return {
|
|
31459
|
+
line: call.location.line,
|
|
31460
|
+
receiver: "http.SetCookie",
|
|
31461
|
+
missingSecure,
|
|
31462
|
+
missingHttpOnly,
|
|
31463
|
+
optionsPresent: true
|
|
31464
|
+
};
|
|
31465
|
+
}
|
|
31466
|
+
// ---------------- Rust ----------------
|
|
31467
|
+
detectRustSetCookieFormat(code) {
|
|
31468
|
+
const out2 = [];
|
|
31469
|
+
const re = new RegExp(RUST_SET_COOKIE_MACRO_RE.source, RUST_SET_COOKIE_MACRO_RE.flags);
|
|
31470
|
+
let m;
|
|
31471
|
+
while ((m = re.exec(code)) !== null) {
|
|
31472
|
+
const macro = m[1] ?? "";
|
|
31473
|
+
const body2 = m[2] ?? "";
|
|
31474
|
+
const missingSecure = !/\bSecure\b/.test(body2);
|
|
31475
|
+
const missingHttpOnly = !/\bHttpOnly\b/.test(body2);
|
|
31476
|
+
if (!missingSecure && !missingHttpOnly) continue;
|
|
31477
|
+
const line = code.slice(0, m.index).split("\n").length;
|
|
31478
|
+
out2.push({
|
|
31479
|
+
line,
|
|
31480
|
+
receiver: macro,
|
|
31481
|
+
missingSecure,
|
|
31482
|
+
missingHttpOnly,
|
|
31483
|
+
optionsPresent: true
|
|
31484
|
+
});
|
|
31485
|
+
}
|
|
31486
|
+
return out2;
|
|
31487
|
+
}
|
|
31417
31488
|
emit(ctx, file, det, flavor) {
|
|
31418
31489
|
const missing = [];
|
|
31419
|
-
if (det.missingSecure)
|
|
31420
|
-
|
|
31421
|
-
|
|
31490
|
+
if (det.missingSecure) {
|
|
31491
|
+
missing.push(
|
|
31492
|
+
flavor === "js" ? "`secure: true`" : flavor === "python" ? "`secure=True`" : flavor === "java" ? "`setSecure(true)`" : flavor === "go" ? "`Secure: true`" : "`Secure` attribute"
|
|
31493
|
+
);
|
|
31494
|
+
}
|
|
31495
|
+
if (det.missingHttpOnly) {
|
|
31496
|
+
missing.push(
|
|
31497
|
+
flavor === "js" ? "`httpOnly: true`" : flavor === "python" ? "`httponly=True`" : flavor === "java" ? "`setHttpOnly(true)`" : flavor === "go" ? "`HttpOnly: true`" : "`HttpOnly` attribute"
|
|
31498
|
+
);
|
|
31499
|
+
}
|
|
31500
|
+
const fix = flavor === "js" ? 'Pass `{ secure: true, httpOnly: true, sameSite: "lax" }` as the third argument to `res.cookie()`.' : flavor === "python" ? 'Pass `secure=True, httponly=True, samesite="Lax"` to `response.set_cookie(...)`.' : flavor === "java" ? "After constructing the cookie, call `cookie.setSecure(true)` and `cookie.setHttpOnly(true)` before adding it to the response." : flavor === "go" ? "Set `Secure: true` and `HttpOnly: true` on the `http.Cookie` struct literal passed to `http.SetCookie`." : "Append `; Secure; HttpOnly` to the `Set-Cookie` header string.";
|
|
31422
31501
|
ctx.addFinding({
|
|
31423
31502
|
id: `${this.name}-${file}-${det.line}`,
|
|
31424
31503
|
pass: this.name,
|
|
@@ -11522,6 +11522,11 @@ var DEFAULT_SINKS = [
|
|
|
11522
11522
|
{ method: "exec", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
11523
11523
|
{ method: "compile", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
11524
11524
|
{ method: "__import__", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
11525
|
+
// Python dynamic import — `importlib.import_module(taint)` parallels Java's
|
|
11526
|
+
// `Class.forName`. The bare `__import__` entry above also matches the
|
|
11527
|
+
// `importlib.__import__` form because the sink-matcher is class-agnostic
|
|
11528
|
+
// when a classless entry exists. Sprint 56 #183.
|
|
11529
|
+
{ method: "import_module", class: "importlib", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
11525
11530
|
// Python Deserialization — language-scoped so the lowercase `yaml` / `pickle`
|
|
11526
11531
|
// module names don't collide with Java locals named `yaml` (SnakeYAML usage).
|
|
11527
11532
|
{ method: "loads", class: "pickle", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
@@ -11779,6 +11784,15 @@ var DEFAULT_SINKS = [
|
|
|
11779
11784
|
// Standard library logging
|
|
11780
11785
|
{ method: "println!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2] },
|
|
11781
11786
|
{ method: "eprintln!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2] },
|
|
11787
|
+
// log:: namespaced forms — the Rust macro extractor preserves the full
|
|
11788
|
+
// path prefix in `method_name` (`log::info!`), so the bare entries above
|
|
11789
|
+
// only match the imported form `use log::info; info!(...)`. Sprint 56 #182 Slice A.
|
|
11790
|
+
{ method: "log::info!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11791
|
+
{ method: "log::warn!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11792
|
+
{ method: "log::error!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11793
|
+
{ method: "log::debug!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11794
|
+
{ method: "log::trace!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11795
|
+
{ method: "log::log!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11782
11796
|
// Rust sqlx SQL Injection
|
|
11783
11797
|
{ method: "query", class: "sqlx", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
|
11784
11798
|
{ method: "query_as", class: "sqlx", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
|
@@ -11456,6 +11456,11 @@ var DEFAULT_SINKS = [
|
|
|
11456
11456
|
{ method: "exec", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
11457
11457
|
{ method: "compile", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
11458
11458
|
{ method: "__import__", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
11459
|
+
// Python dynamic import — `importlib.import_module(taint)` parallels Java's
|
|
11460
|
+
// `Class.forName`. The bare `__import__` entry above also matches the
|
|
11461
|
+
// `importlib.__import__` form because the sink-matcher is class-agnostic
|
|
11462
|
+
// when a classless entry exists. Sprint 56 #183.
|
|
11463
|
+
{ method: "import_module", class: "importlib", type: "code_injection", cwe: "CWE-94", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
11459
11464
|
// Python Deserialization — language-scoped so the lowercase `yaml` / `pickle`
|
|
11460
11465
|
// module names don't collide with Java locals named `yaml` (SnakeYAML usage).
|
|
11461
11466
|
{ method: "loads", class: "pickle", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
@@ -11713,6 +11718,15 @@ var DEFAULT_SINKS = [
|
|
|
11713
11718
|
// Standard library logging
|
|
11714
11719
|
{ method: "println!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2] },
|
|
11715
11720
|
{ method: "eprintln!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2] },
|
|
11721
|
+
// log:: namespaced forms — the Rust macro extractor preserves the full
|
|
11722
|
+
// path prefix in `method_name` (`log::info!`), so the bare entries above
|
|
11723
|
+
// only match the imported form `use log::info; info!(...)`. Sprint 56 #182 Slice A.
|
|
11724
|
+
{ method: "log::info!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11725
|
+
{ method: "log::warn!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11726
|
+
{ method: "log::error!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11727
|
+
{ method: "log::debug!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11728
|
+
{ method: "log::trace!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11729
|
+
{ method: "log::log!", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2], languages: ["rust"] },
|
|
11716
11730
|
// Rust sqlx SQL Injection
|
|
11717
11731
|
{ method: "query", class: "sqlx", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
|
11718
11732
|
{ method: "query_as", class: "sqlx", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.113.0",
|
|
4
4
|
"description": "High-performance Static Application Security Testing (SAST) library for detecting security vulnerabilities through taint analysis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|