circle-ir 3.182.0 → 3.186.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 +182 -0
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/passes/language-sources-pass.d.ts.map +1 -1
- package/dist/analysis/passes/language-sources-pass.js +207 -0
- package/dist/analysis/passes/language-sources-pass.js.map +1 -1
- package/dist/analysis/taint-matcher.js +27 -1
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/browser/circle-ir.js +312 -2
- package/dist/core/circle-ir-core.cjs +190 -1
- package/dist/core/circle-ir-core.js +190 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/analysis/config-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,UAAU,EACX,MAAM,oBAAoB,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAEjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,aAAa,EAAE,CAiB1E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG;IACtD,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC,CAcA;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,mBAAmB,EAAE,GAC7B,kBAAkB,EAAE,CAQtB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,MAAM,EAAE,EACxB,YAAY,EAAE,MAAM,EAAE,EACtB,qBAAqB,GAAE,MAAM,EAAO,GACnC,WAAW,CAYb;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/analysis/config-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,UAAU,EACX,MAAM,oBAAoB,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAEjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,aAAa,EAAE,CAiB1E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG;IACtD,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC,CAcA;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,mBAAmB,EAAE,GAC7B,kBAAkB,EAAE,CAQtB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,MAAM,EAAE,EACxB,YAAY,EAAE,MAAM,EAAE,EACtB,qBAAqB,GAAE,MAAM,EAAO,GACnC,WAAW,CAYb;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,EAymB1C,CAAC;AA+KF,eAAO,MAAM,aAAa,EAAE,WAAW,EA2wDtC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,EA4chD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,kBAAkB,EAiDtD,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAO9C;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAAU,EA8F5C,CAAC"}
|
|
@@ -522,6 +522,49 @@ export const DEFAULT_SOURCES = [
|
|
|
522
522
|
// Server-side interceptor receives `Metadata headers`; `headers.get(KEY)`
|
|
523
523
|
// returns caller-supplied header values.
|
|
524
524
|
{ method: 'get', class: 'Metadata', type: 'http_header', severity: 'high', return_tainted: true, languages: ['java'] },
|
|
525
|
+
// --- WebSocket transport channels (cognium-dev #213 second slice) ---
|
|
526
|
+
//
|
|
527
|
+
// Server-side WebSocket handlers receive attacker-authored frames on
|
|
528
|
+
// every call to a receive-shaped method. Untrusted the moment they
|
|
529
|
+
// return, regardless of any application-level auth on the socket.
|
|
530
|
+
//
|
|
531
|
+
// Python — FastAPI / Starlette (`from fastapi import WebSocket`):
|
|
532
|
+
// data = await websocket.receive_text()
|
|
533
|
+
// data = await websocket.receive_bytes()
|
|
534
|
+
// data = await websocket.receive_json() # parsed dict/list
|
|
535
|
+
// data = await websocket.receive() # {'type', 'text'|'bytes'}
|
|
536
|
+
{ method: 'receive_text', class: 'WebSocket', type: 'network_input', severity: 'high', return_tainted: true, languages: ['python'] },
|
|
537
|
+
{ method: 'receive_bytes', class: 'WebSocket', type: 'network_input', severity: 'high', return_tainted: true, languages: ['python'] },
|
|
538
|
+
{ method: 'receive_json', class: 'WebSocket', type: 'http_body', severity: 'high', return_tainted: true, languages: ['python'] },
|
|
539
|
+
//
|
|
540
|
+
// `receive` intentionally class-scoped to WebSocket (Starlette pattern).
|
|
541
|
+
// Broadening to unqualified would collide with queue/signal `.receive()`.
|
|
542
|
+
{ method: 'receive', class: 'WebSocket', type: 'network_input', severity: 'high', return_tainted: true, languages: ['python'] },
|
|
543
|
+
// Django Channels `AsyncJsonWebsocketConsumer` / `WebsocketConsumer`
|
|
544
|
+
// expose the same receive_* names on `self`; the class filter matches
|
|
545
|
+
// `WebSocket` only, so add unqualified fallbacks for the receive_json /
|
|
546
|
+
// receive_text convention (broad — no class filter possible without
|
|
547
|
+
// hardcoding Django's consumer names).
|
|
548
|
+
{ method: 'receive_json', type: 'http_body', severity: 'high', return_tainted: true, languages: ['python'] },
|
|
549
|
+
{ method: 'receive_text', type: 'network_input', severity: 'high', return_tainted: true, languages: ['python'] },
|
|
550
|
+
{ method: 'receive_bytes', type: 'network_input', severity: 'high', return_tainted: true, languages: ['python'] },
|
|
551
|
+
// Go — gorilla/websocket (`github.com/gorilla/websocket`):
|
|
552
|
+
// messageType, message, err := conn.ReadMessage()
|
|
553
|
+
// _, r, err := conn.NextReader()
|
|
554
|
+
{ method: 'ReadMessage', class: 'Conn', type: 'network_input', severity: 'high', return_tainted: true, languages: ['go'] },
|
|
555
|
+
{ method: 'NextReader', class: 'Conn', type: 'network_input', severity: 'high', return_tainted: true, languages: ['go'] },
|
|
556
|
+
// nhooyr.io/websocket exposes a `Read` method on `*websocket.Conn`;
|
|
557
|
+
// signature is `func (c *Conn) Read(ctx) (MessageType, []byte, error)`.
|
|
558
|
+
{ method: 'Read', class: 'Conn', type: 'network_input', severity: 'high', return_tainted: true, languages: ['go'] },
|
|
559
|
+
// Java — Jakarta / Java WebSocket API (`javax.websocket` / `jakarta.websocket`):
|
|
560
|
+
// session.getBasicRemote().sendText(input); // OUT (not a source)
|
|
561
|
+
// @OnMessage public void onMessage(String msg) — `msg` is a callback
|
|
562
|
+
// param, not a return; handled via param_tainted when annotation is set.
|
|
563
|
+
{ annotation: 'OnMessage', type: 'network_input', severity: 'high', param_tainted: true, languages: ['java'] },
|
|
564
|
+
// Spring `@MessageMapping` STOMP-over-WebSocket handlers receive
|
|
565
|
+
// untrusted payloads on every dispatched frame.
|
|
566
|
+
{ annotation: 'MessageMapping', type: 'http_body', severity: 'high', param_tainted: true, languages: ['java'] },
|
|
567
|
+
{ annotation: 'SubscribeMapping', type: 'http_body', severity: 'high', param_tainted: true, languages: ['java'] },
|
|
525
568
|
// --- Cache reads (second-order taint — Redis / Memcached / Django cache) ---
|
|
526
569
|
// The cache round-trip is a canonical second-order sink: whatever was
|
|
527
570
|
// written previously (potentially attacker-controlled) resurfaces on read.
|
|
@@ -2583,6 +2626,91 @@ export const DEFAULT_SANITIZERS = [
|
|
|
2583
2626
|
// Command injection - shell escaping
|
|
2584
2627
|
{ method: 'quote', class: 'shell', removes: ['command_injection'] },
|
|
2585
2628
|
{ method: 'escape', class: 'shell-escape', removes: ['command_injection'] },
|
|
2629
|
+
// JS/Node — additional XSS/HTML encoders (cognium-dev #213 sixth slice).
|
|
2630
|
+
//
|
|
2631
|
+
// he.encode(x) / he.escape(x) — `he` npm package
|
|
2632
|
+
// sanitizeHtml(x) — `sanitize-html` npm
|
|
2633
|
+
// xss(x) / filterXSS(x) — `xss` npm (Yahoo)
|
|
2634
|
+
// escapeHtml(x) / escapeHTML(x) — common bare helpers
|
|
2635
|
+
// entities.encode(x) / entities.escape(x) — `entities` npm
|
|
2636
|
+
// xssFilters.inHTMLData(x) / inHTMLComment(x) / uriInHTMLData(x)
|
|
2637
|
+
// — `xss-filters` npm (Yahoo)
|
|
2638
|
+
//
|
|
2639
|
+
// `external_taint_escape` is included alongside `xss` — the CWE-668
|
|
2640
|
+
// fallback fires on any call receiving tainted data that the engine
|
|
2641
|
+
// does not otherwise recognize. Since these functions are explicitly
|
|
2642
|
+
// registered as sanitizers (they PURIFY input), they should also
|
|
2643
|
+
// suppress the fallback so a `res.send(sanitizeHtml(x))` flow does
|
|
2644
|
+
// not report an external-taint-escape at the sanitizer call itself.
|
|
2645
|
+
{ method: 'encode', class: 'he', removes: ['xss', 'external_taint_escape'] },
|
|
2646
|
+
{ method: 'escape', class: 'he', removes: ['xss', 'external_taint_escape'] },
|
|
2647
|
+
{ method: 'sanitizeHtml', removes: ['xss', 'external_taint_escape'] },
|
|
2648
|
+
{ method: 'xss', removes: ['xss', 'external_taint_escape'] },
|
|
2649
|
+
{ method: 'filterXSS', removes: ['xss', 'external_taint_escape'] },
|
|
2650
|
+
{ method: 'escapeHtml', removes: ['xss', 'external_taint_escape'] },
|
|
2651
|
+
{ method: 'escapeHTML', removes: ['xss', 'external_taint_escape'] },
|
|
2652
|
+
{ method: 'encode', class: 'entities', removes: ['xss', 'external_taint_escape'] },
|
|
2653
|
+
{ method: 'escape', class: 'entities', removes: ['xss', 'external_taint_escape'] },
|
|
2654
|
+
// xss-filters: context-specific helpers, all XSS-safe by construction.
|
|
2655
|
+
{ method: 'inHTMLData', class: 'xssFilters', removes: ['xss', 'external_taint_escape'] },
|
|
2656
|
+
{ method: 'inHTMLComment', class: 'xssFilters', removes: ['xss', 'external_taint_escape'] },
|
|
2657
|
+
{ method: 'uriInHTMLData', class: 'xssFilters', removes: ['xss', 'external_taint_escape'] },
|
|
2658
|
+
// JS/Node — SQL escaping (in addition to the mysql class above).
|
|
2659
|
+
//
|
|
2660
|
+
// SqlString.escape / .escapeId — `sqlstring` npm (raw
|
|
2661
|
+
// escape used by mysql /
|
|
2662
|
+
// node-mysql2 drivers)
|
|
2663
|
+
// pgFormat(sql, ...args) / format(bare) — `pg-format` npm
|
|
2664
|
+
// SQL.raw / SQL(bare) — `sql-template-strings`
|
|
2665
|
+
//
|
|
2666
|
+
// Bare `format` is intentionally NOT registered — it collides with
|
|
2667
|
+
// string.format-style helpers unrelated to SQL. Callers should use the
|
|
2668
|
+
// qualified form.
|
|
2669
|
+
{ method: 'escape', class: 'SqlString', removes: ['sql_injection', 'external_taint_escape'] },
|
|
2670
|
+
{ method: 'escapeId', class: 'SqlString', removes: ['sql_injection', 'external_taint_escape'] },
|
|
2671
|
+
{ method: 'format', class: 'SqlString', removes: ['sql_injection', 'external_taint_escape'] },
|
|
2672
|
+
{ method: 'format', class: 'pgFormat', removes: ['sql_injection', 'external_taint_escape'] },
|
|
2673
|
+
{ method: 'ident', class: 'pgFormat', removes: ['sql_injection', 'external_taint_escape'] },
|
|
2674
|
+
{ method: 'literal', class: 'pgFormat', removes: ['sql_injection', 'external_taint_escape'] },
|
|
2675
|
+
// JS/Node — crypto.randomUUID() and Node's crypto.randomBytes(...)toString()
|
|
2676
|
+
// produce cryptographically-secure typed strings that cannot carry
|
|
2677
|
+
// attacker-injected payload. Registered as type coercion.
|
|
2678
|
+
{ method: 'randomUUID', class: 'crypto', removes: ['sql_injection', 'nosql_injection', 'command_injection', 'path_traversal', 'code_injection', 'xss'] },
|
|
2679
|
+
// Bare `randomUUID()` alias — `import { randomUUID } from 'crypto'`.
|
|
2680
|
+
{ method: 'randomUUID', removes: ['sql_injection', 'nosql_injection', 'command_injection', 'path_traversal', 'code_injection', 'xss'] },
|
|
2681
|
+
// JS/Node — URL construction. `new URL(x, base)` (constructor-call
|
|
2682
|
+
// matched by method_name === 'URL') and `URLSearchParams.toString()`
|
|
2683
|
+
// safely encode components for URL context.
|
|
2684
|
+
{ method: 'toString', class: 'URLSearchParams', removes: ['ssrf', 'open_redirect', 'xss'] },
|
|
2685
|
+
// Go — additional sanitizers (cognium-dev #213 sixth slice).
|
|
2686
|
+
//
|
|
2687
|
+
// regexp.QuoteMeta(x) — mirror of Python re.escape; strips regex
|
|
2688
|
+
// metacharacters so downstream compile/match
|
|
2689
|
+
// cannot execute attacker-crafted patterns.
|
|
2690
|
+
// bluemonday.Sanitize — dominant Go HTML sanitizer library
|
|
2691
|
+
// (`microcosm-cc/bluemonday`). Called on a
|
|
2692
|
+
// Policy value returned by UGCPolicy() /
|
|
2693
|
+
// StrictPolicy() / etc. Match by method name
|
|
2694
|
+
// alone — Policy is the receiver type.
|
|
2695
|
+
// net.ParseIP(x) — validates the input is a well-formed IP;
|
|
2696
|
+
// returns nil for bad input (developer must
|
|
2697
|
+
// check, but the sanitizer only applies when
|
|
2698
|
+
// the parsed IP flows onward).
|
|
2699
|
+
// sql.Named(name, val) — parameterized query binding.
|
|
2700
|
+
{ method: 'QuoteMeta', class: 'regexp', removes: ['redos', 'code_injection', 'external_taint_escape'] },
|
|
2701
|
+
{ method: 'Sanitize', class: 'bluemonday', removes: ['xss', 'external_taint_escape'] },
|
|
2702
|
+
{ method: 'Sanitize', class: 'Policy', removes: ['xss', 'external_taint_escape'] },
|
|
2703
|
+
// Bare `Sanitize` — the receiver is a Policy variable (`p := bluemonday.UGCPolicy(); p.Sanitize(x)`).
|
|
2704
|
+
// `Policy` class-matching only fires when the IR resolves the receiver type;
|
|
2705
|
+
// since Go DFG rarely propagates the type of a locally-assigned variable
|
|
2706
|
+
// from a package factory call, we also register the bare method name.
|
|
2707
|
+
// Narrow FP risk: `Sanitize` bare is uncommon outside bluemonday context.
|
|
2708
|
+
{ method: 'Sanitize', removes: ['xss', 'external_taint_escape'] },
|
|
2709
|
+
{ method: 'SanitizeBytes', class: 'bluemonday', removes: ['xss', 'external_taint_escape'] },
|
|
2710
|
+
{ method: 'SanitizeBytes', class: 'Policy', removes: ['xss', 'external_taint_escape'] },
|
|
2711
|
+
{ method: 'SanitizeBytes', removes: ['xss', 'external_taint_escape'] },
|
|
2712
|
+
{ method: 'ParseIP', class: 'net', removes: ['ssrf', 'command_injection', 'path_traversal', 'external_taint_escape'] },
|
|
2713
|
+
{ method: 'Named', class: 'sql', removes: ['sql_injection', 'external_taint_escape'] },
|
|
2586
2714
|
// =========================================================================
|
|
2587
2715
|
// Python Sanitizers
|
|
2588
2716
|
// =========================================================================
|
|
@@ -2627,6 +2755,60 @@ export const DEFAULT_SANITIZERS = [
|
|
|
2627
2755
|
// Python Type coercion
|
|
2628
2756
|
{ method: 'int', removes: ['sql_injection', 'command_injection', 'xss'] },
|
|
2629
2757
|
{ method: 'float', removes: ['sql_injection', 'command_injection'] },
|
|
2758
|
+
// Python URL encoding (cognium-dev #213 fifth slice).
|
|
2759
|
+
//
|
|
2760
|
+
// urllib.parse.quote(x) — RFC-3986 percent-encode; safe for URL path
|
|
2761
|
+
// urllib.parse.quote_plus(x) — same + space→+; safe for query string
|
|
2762
|
+
// urllib.parse.urlencode(d) — encode a dict of pairs
|
|
2763
|
+
//
|
|
2764
|
+
// Bounded to URL-context sinks. Class-scoped to the specific
|
|
2765
|
+
// `urllib.parse` receiver to avoid colliding with unrelated bare
|
|
2766
|
+
// `quote(...)` calls in other libraries.
|
|
2767
|
+
{ method: 'quote', class: 'urllib.parse', removes: ['ssrf', 'open_redirect', 'xss', 'path_traversal'] },
|
|
2768
|
+
{ method: 'quote_plus', class: 'urllib.parse', removes: ['ssrf', 'open_redirect', 'xss', 'path_traversal'] },
|
|
2769
|
+
{ method: 'urlencode', class: 'urllib.parse', removes: ['ssrf', 'open_redirect', 'xss'] },
|
|
2770
|
+
// Bare aliases — `from urllib.parse import quote` then unqualified.
|
|
2771
|
+
{ method: 'quote_plus', removes: ['ssrf', 'open_redirect', 'xss', 'path_traversal'] },
|
|
2772
|
+
{ method: 'urlencode', removes: ['ssrf', 'open_redirect', 'xss'] },
|
|
2773
|
+
// `quote` bare is intentionally NOT registered — it collides with
|
|
2774
|
+
// shlex.quote (bare-imported) which is a command_injection sanitizer,
|
|
2775
|
+
// not a URL sanitizer. The class-scoped variant above catches the
|
|
2776
|
+
// qualified `urllib.parse.quote(...)` shape; unqualified callers who
|
|
2777
|
+
// want URL-context credit should use `quote_plus` (which does not
|
|
2778
|
+
// collide with any command_injection sanitizer).
|
|
2779
|
+
// Python XSS — additional common sanitizers.
|
|
2780
|
+
//
|
|
2781
|
+
// bleach.clean(...) — already covered above (line 2898)
|
|
2782
|
+
// bleach.linkify(...) — turns URLs into anchor tags; sanitizes as well
|
|
2783
|
+
// django.utils.html.escape / strip_tags — Django's XSS escape helpers
|
|
2784
|
+
// jinja2.escape — Jinja2's Markup escape (aliased from markupsafe)
|
|
2785
|
+
// flask.escape — Flask re-export of markupsafe.escape
|
|
2786
|
+
// saxutils.escape — stdlib xml.sax.saxutils.escape for XML docs
|
|
2787
|
+
{ method: 'linkify', class: 'bleach', removes: ['xss'] },
|
|
2788
|
+
// Bare `linkify(...)` alias — `from bleach import linkify`.
|
|
2789
|
+
{ method: 'linkify', removes: ['xss'] },
|
|
2790
|
+
{ method: 'escape', class: 'django.utils.html', removes: ['xss'] },
|
|
2791
|
+
{ method: 'strip_tags', class: 'django.utils.html', removes: ['xss'] },
|
|
2792
|
+
{ method: 'escape', class: 'jinja2', removes: ['xss'] },
|
|
2793
|
+
{ method: 'escape', class: 'flask', removes: ['xss'] },
|
|
2794
|
+
{ method: 'escape', class: 'saxutils', removes: ['xss'] },
|
|
2795
|
+
{ method: 'escape', class: 'xml.sax.saxutils', removes: ['xss'] },
|
|
2796
|
+
{ method: 'quoteattr', class: 'saxutils', removes: ['xss'] },
|
|
2797
|
+
{ method: 'quoteattr', class: 'xml.sax.saxutils', removes: ['xss'] },
|
|
2798
|
+
// Python ReDoS — `re.escape(user)` when building a regex from user input
|
|
2799
|
+
// strips regex metacharacters. Downstream `re.compile / re.match` cannot
|
|
2800
|
+
// interpret user-supplied alternations or quantifiers. Also covers the
|
|
2801
|
+
// `code_injection` categorization that `re.compile` currently emits
|
|
2802
|
+
// (a re.escape-wrapped pattern cannot execute anything, so both are safe).
|
|
2803
|
+
{ method: 'escape', class: 're', removes: ['redos', 'code_injection'] },
|
|
2804
|
+
// Python SQLAlchemy — `text(...).bindparams(...)` binds params safely.
|
|
2805
|
+
// The `bindparams` call is the sanitizer; the parent `text` wraps the
|
|
2806
|
+
// template. Also add `expression.literal` for explicit SQL literals.
|
|
2807
|
+
{ method: 'bindparams', removes: ['sql_injection'] },
|
|
2808
|
+
// psycopg2 sql-composition helpers
|
|
2809
|
+
{ method: 'Identifier', class: 'sql', removes: ['sql_injection'] },
|
|
2810
|
+
{ method: 'Literal', class: 'sql', removes: ['sql_injection'] },
|
|
2811
|
+
{ method: 'Placeholder', class: 'sql', removes: ['sql_injection'] },
|
|
2630
2812
|
// =========================================================================
|
|
2631
2813
|
// Rust Sanitizers
|
|
2632
2814
|
// =========================================================================
|