▸ WAVEYUG.IN  v…
🛡️ RUDRA v… — 9-Stage Pipeline · … Rules · PHP · JS · Python · Ruby · Java · Go · C++ · India Compliance · Claude AI Fix · v471: 🏗️ CWE-295 SEVERITY-ESCALATION ARCHITECTURE FIX (user-driven recheck, Hinglish) — user reported CWE-295 (TLS/SSL verification disabled) findings still showing CRITICAL in testing despite v458's contextual downgrade, plus flagged that the v458 escalation signals only ever looked at the literal matched line, missing propagated cases. ROOT CAUSE #1 (severity): applySeverityRules() RULE 0's gate required `SEV_ORDER[r.s] < SEV_ORDER['critical']`, so the whole v458 contextual policy only ran for findings that ENTERED below critical — any OTHER detector hardcoding s:'critical' for a CWE-295 pattern bypassed it entirely and stayed critical forever. Confirmed two live instances via call-graph audit: (1) detectCloudMisconfig()'s ad-hoc Go InsecureSkipVerify check (~line 12514) was a near-exact regex duplicate of DB_TLSVERIFY_005 (same /InsecureSkipVerify\s*:\s*true/i pattern) but hardcoded critical, producing a duplicate always-critical finding alongside DB_TLSVERIFY_005's correctly-gated one — REMOVED as a duplicate detector (same class as the v447 pickle.loads()/v469 SSRF triple-check cleanups); (2) DB_KOTLIN_SEC_012 (TrustManager, empty checkServerTrusted) also hardcodes critical and was silently exempt from the policy. Fixed by removing the SEV_ORDER gate so EVERY CWE-295 finding — whatever severity it entered with, from whatever detector — now gets the same real-signal verdict (deliberate behavior change: DB_KOTLIN_SEC_012 now defaults to HIGH like the DB_TLSVERIFY_* family unless a real signal is present). ROOT CAUSE #2 (propagation/context accuracy): the sensitive-data/dynamic-target signal check only scanned matchText (the literal matched line), so a signal 1-2 lines away (a token used to build the same request, or the verify flag itself set via a nearby variable) was invisible even though detection fired correctly. applySeverityRules() now takes an optional `code` param and — when the caller supplies it plus a finding line number — folds in a real ±8-line getContext() window alongside matchText for both signal checks; both call sites (runValidationEngine and postProcessResults) now pass `code` through. NOT full variable-alias/taint-graph tracking (a flag set several functions away and passed in by name still won't be seen) — flagged by the user themselves as a genuinely separate, deeper gap for its own pass. Verified via a Node harness running the real extracted getContext()/applySeverityRules()/SEV_ENGINE source (not a rewritten copy) against 8 cases: Go InsecureSkipVerify with no signal → HIGH (was duplicated CRITICAL); Kotlin TrustManager entering as hardcoded critical with no signal → downgrades to HIGH; same case with a real signal 3 lines away → escalates to CRITICAL (the window fix); same signal 21 lines away → stays HIGH (window correctly bounded, not a whole-file scan); Python verify=False with the request target built from req. 2 lines later → escalates to CRITICAL; the v458 fix-3 regression (Node's own "rejectUnauthorized" text self-triggering the old bare "authoriz" signal) confirmed still fixed; genuine same-line signal still escalates (baseline preserved); missing code/line falls back to matchText-only with no throw. All 10 inline <script> blocks syntax-clean via node --check post-edit. Also did a due-diligence check on the user's separately-flagged #9 (multi-file scanning v444 vs v466/v467 discrepancy): confirmed both the v444 per-file Stage 3/3.5/4.5 wiring (sourceFile tagging, 1,000,000-line-per-file offset) and the v467 O(1) taint-lookup helpers (_extractIdentifiers/_findTaintedVarIn/_hasTaintedVarIn) are still present and wired, no obvious regression found by static audit — flagged for the user to confirm whether the residual symptom is on multi-file (many files/GitHub repo scan) or large single-file scans specifically, since those are two different code paths with two different prior fixes, and to share a concrete repro so it can be isolated the same empirical way as the fixes above. v470: 🎯 SSRF WINDOW-MATCH FIX (2-part, user-driven recheck) — user reported (in Hinglish) a real SSRF false-positive/duplicate-finding bug in the Batch E wiring (~line 21489). PART 1: detectSSRFInternalStrict()'s core match tested fetch/axios/curl and localhost/127.0.0.1/private-IP INDEPENDENTLY against the whole ±5-line getContext() window instead of requiring co-occurrence on the same line — so any fetch/axios/curl call within 5 lines of an unrelated localhost mention (a comment, a different call, a log line) false-fired as CRITICAL SSRF; same bug class as the existing v414 SQLI-001 line-scoping fix. Fixed by requiring both signals to match on the SAME line within the window. PART 2 (found on a second recheck pass, via direct Node test execution, not static reading): even after Part 1, the wiring loop treats every line matching the loose outer fetch/axios/curl/dns.lookup substring test (which also matches inside identifiers like "fetchMeta") as its own trigger and reported any hit at that TRIGGER line, not the real one — so with a ±5-line window, every trigger within 5 lines of one real match independently rediscovered it and reported a SEPARATE duplicate finding at its own (wrong) line; reproduced directly: 2 fetch() calls a few lines apart, only one genuinely hitting localhost, produced 4 findings instead of 1. Fixed by having detectSSRFInternalStrict() also return which line within its context actually matched (_contextLineOffset), and having the wiring resolve the real absolute line and dedupe on it instead of the trigger line. Verified via 7 direct Node test cases (not a full harness, per the user's own instruction): original FP scenario now clean; genuine same-line SSRF with a taint marker nearby still fires once at the correct line; the fetchMeta-substring-trigger + real AWS-metadata-endpoint case now yields exactly 1 finding (was 2 pre-Part-2); DNS-rebinding guard still suppressed; the pre-existing v445 hardcoded-localhost-no-taint-marker exemption still suppresses correctly, unchanged by design; two genuinely separate real vulnerabilities 12 lines apart still produce 2 distinct findings, not over-merged. All 13 <script> blocks syntax-clean via node --check after both edits — zero other detection/scoring logic touched. KNOWN NOT YET AUDITED (flagged, not fixed): applyMissingFixes() (~line 12179) calls the same detectSSRFInternalStrict() but unconditionally overwrites the returned .line with its own trigger line after the object spread — same mis-attribution class as Part 2, left untouched. applyProFixes() (~line 12198) has a THIRD, fully independent SSRF check via isInternalSSRFContext() — not inspected. The "GO RULE 1: SSRF Internal Force" block (~line 18525) builds its own equivalent unscoped ±5/±6-line window and re-tests the same two patterns independently — the same Part-1-class flaw, also untouched. Any of these three could still contribute SSRF duplicates/FPs if the issue isn't fully gone after this fix. v469: 🏷️ CATEGORY REPORTING FIX — user asked (in Hinglish) whether the category shown for each detected vulnerability in the report actually matches what was caught. Verified via a Node VM harness running the real normalizeDB()→normalizeRule()→runRules()→postProcessResults() pipeline against 21+18+6 findings across PHP/JS/Python fixtures spanning ~20 vuln classes: confirmed EVERY finding's displayed category (renderResults()'s safeCat/v.category badge, and the same field in exportPDF()) collapsed to one of only 3 generic buckets — 'Injection'/'Data Exposure'/'Misconfiguration' — because normalizeRule() (called for all 1351 DB{} rules via normalizeDB()'s `rules.map(normalizeRule)`, a bare function reference easy to mis-grep as unused) falls back to inferCategory(cwe) whenever a rule has no explicit .category (1349 of 1351 don't), and that function only recognized ~35 CWEs bucketed into those 3 labels. A second, smaller path was worse: a few ad-hoc flow/second-order detector functions push finding objects with no .category field at all, rendering as literal "GENERAL". FIRST DRAFT OF THIS FIX (self-caught on recheck, never shipped as such): made inferCategory(cwe) itself specific and had normalizeRule() prefer a new 134-entry CAT_KEY_LABELS[catKey] lookup, writing the result straight into the existing .category field. A full before/after diff of every finding field (not just category) caught that this was NOT display-only: r.category also feeds `cat = (r.category||r.s||'').toLowerCase()` in at least two separate severity-classification spots (the "RULE 3: Class-based floor" block and the postSorted/dedupedResults.map severity-normalization pass), tested against patterns like /sqli|rce|cmd|command/, /\bxss\b|csrf|redirect|ssrf|.../, /debug|infoleak/, and per-key .includes(catKey) checks. Those checks were silently always-false before (the 3 bucket words never match those patterns) — making category specific would have made them fire for the first time across 1351 rules with zero targeted test coverage for that interaction; the two test fixtures already showed a real _severityReason path change (same final severity by luck, not by verification) for CWE-611/CWE-94 findings. CORRECTED FIX: inferCategory(cwe) and the .category field are untouched — byte-for-byte the original 3-bucket behavior, so every existing internal consumer keeps working exactly as before. A brand-new inferSpecificCategory(cwe) + CAT_KEY_LABELS populate a separate, purely additive .specificCategory field instead (normalizeRule(r, catKey) sets it; the runRules() finding-builder's `...rule` spread carries it through automatically; postProcessResults()'s entry-point stamp — same pattern as the existing v198 _lang stamp — fills it for the ad-hoc-detector findings too). Only the three human-facing report surfaces were changed, to prefer specificCategory||category: renderResults()'s safeCat, exportPDF()'s category badge, and the Markdown report's Category table row. Verified twice: (1) full field-by-field diff of every finding, before vs after, across all three language fixtures — 0 differences anywhere outside the new specificCategory field itself, confirming zero effect on severity/dedup/confidence/anything else; (2) 0 findings left showing a missing/generic-bucket category across all three fixtures. All 13 <script> blocks syntax-clean via node --check (including one self-introduced brace-deletion mistake, caught by the same syntax check and fixed before shipping). KNOWN RESIDUAL GAP (pre-existing, not introduced by this fix): a handful of individual rules live under a DB bucket key that doesn't match their actual content (e.g. a "helmet() security headers missing" rule filed under insecure_file_ops, a pickle.loads() rule filed under crypto) — CAT_KEY_LABELS trusts the bucket key, so these specific rules can show a bucket-derived specificCategory that's a worse fit than the vulnerability itself; a full fix needs a rule-by-rule bucket-placement audit across all 1351 rules, out of scope here. v467: ⚡ PERFORMANCE FIX — root cause of large-file scan hangs/timeouts (and the resulting non-deterministic "rule fires but finding missing" reports): getTaintInfo()/hasTaintedVar() (the taint-lookup called for every matched line × every rule inside runRules()) looped Object.keys(varMap) and compiled a fresh, uncached new RegExp() per variable per call — O(rules × lines × totalVariablesInFile). On a large file this made the scan slow enough to hang/timeout mid-scan, so rules queued after the stall never got a chance to push their findings — looked like non-determinism but was really an incomplete scan. Fixed by tokenizing each line once (\$?[A-Za-z_]\w* identifiers) and doing an O(1) varMap lookup instead of iterating every key: applied to getTaintInfo/hasTaintedVar, classifySource, both taint checks inside runRules (CHECK A/C), and all 11 of the same Object.keys(varMap) pattern inside trackVariables itself (multi-hop propagation chains, ES6 destructuring, PHP/JS array-and-object taint, null-coalesce, function-return-taint) — 14 call sites total, via shared helpers _extractIdentifiers/_findTaintedVarIn/_hasTaintedVarIn. Also replaced the rawResults.find(r => r.n === groupKey) dedup lookup (O(R) per rule, O(R²) total as distinct matching rules grow) with a _rawResultsByName Map for O(1) lookup. Deliberately left untouched: 11 further Object.keys(varMap) occurrences inside the advanced-detection functions (detectAdvancedXSS/SQLi/SSRF etc.) — confirmed via call-site audit these run once per scan (not multiplied by rule count), and their loop shape (test each tainted var against sink regexes across the whole file) is inherent to that algorithm, not the same anti-pattern. Verified via an isolated Node vm harness comparing the old vs new getTaintInfo/trackVariables side by side (no live browser/DOM pipeline available in this environment): syntax-clean across all extracted <script> blocks; correctness matched on all synthetic scale tests plus 17 edge cases (substring-name collisions, JS vs PHP style, multi-taint lines) plus 11 targeted pattern tests for every trackVariables code path touched (multi-hop chains, destructuring, array/object taint, null-coalesce, multi-return) — zero mismatches; timing improved 27x-926x on getTaintInfo as varMap size scales from 20 to 400 variables. NOT run in this environment: the full runRules() pipeline end-to-end or the project's 510-case regression suite — needs confirmation in the actual browser/harness. v466: 🏗️ ARCHITECTURE FIX #2 (STAGE 8 emergency fallback) — same anti-pattern as v465, different code path: the `_rawTotal > 0 && results.length === 0` emergency-fallback block (fires only when the real pipeline is confirmed broken and reconstructs raw findings from flowResults/patternResults/advancedResults) had a v337-era `.filter(r => (r.confidence||70) >= 60)` that silently dropped every reconstructed finding below 60% confidence — the exact same "no confidence cutoff, show confidence per item" violation the v465 STRONG_SANITIZERS fix closed, except here it's arguably worse: this path only runs when something upstream is KNOWN to be broken, which is precisely when a genuinely low-confidence raw finding is most valuable to see, not least. Fixed: removed the >=60 filter entirely; the existing `.slice(0,50)` display cap is now preceded by a `.sort((a,b) => confidence desc)` so the 50-item cap (kept as a perf/display limit, not a correctness gate) still surfaces the most-likely-real findings first instead of raw array order. Verified standalone with a synthetic 4-finding fixture spanning confidence 30-90: before fix kept 2/4 (silently dropped the 30% and 45% findings with zero trace); after fix keeps all 4, sorted 90→65→45→30. All 13 <script> blocks syntax-clean via node --check post-edit — zero changes to detection/scoring logic, only this one fallback-reconstruction filter. v465: 🏗️ ARCHITECTURE FIX (verdict-generation stage) — root cause of the repeat "real vulnerability disappears" bug class that v446/v447/v448/v460 each independently rediscovered and narrowed: postProcessResults()'s STRONG_SANITIZERS choke-point (the ~line-23364 block) hard-deleted (finalResult.splice()) any finding whose ±window matched a known-safe pattern, with zero visibility into WHICH findings were removed or WHY. That is a straight violation of the pipeline's own verdict-generation contract ("all findings → report, no confidence cutoff, show confidence per item") — a coarse, line-proximity regex match was being given silent, final veto power over 1351 rules' worth of specific, already-passed contextFilter reasoning. Fixed: matches are no longer deleted. They are DEMOTED — confidence cut to ≤20 (was previously invisible), severity floored to LOW (never raised), and the exact suppression reason + original severity/confidence stamped directly into the finding's description (r.d/r.description) so it survives every downstream render/export path with zero new UI wiring. Net effect: a real bug sitting next to a superficially-matching sanitizer keyword (e.g. "basename" in an unrelated comment) now surfaces as a low-confidence, reviewable finding instead of vanishing before anyone — including a human reviewer or Stage 9's AI review — ever sees it; a genuinely safe line still ends up buried at the bottom of the report at near-zero confidence, which is the correct verdict-generation behavior, not a correctness regression. _v442SuppressedCount (downstream STAGE 8 emergency-fallback gate) now counts demotions instead of deletions — same gating behavior, since a non-empty finalResult from this pass no longer needs a rescue. NOTE for next audit: STAGE 8's own emergency-fallback path (~line 27090) still applies a hard `confidence >= 60` cutoff when it fires — the same anti-pattern one layer up — left untouched this pass since it's a rare fallback-only code path, but should get the same demotion-not-deletion treatment in a follow-up. Verified: all 13 <script> blocks syntax-clean via node --check post-edit; zero regex/rule/contextFilter changes — this pass only touches the post-hoc suppression stage, so all 1351 rules' individual firing logic is byte-for-byte unchanged. v464: 🔍 Recheck against 8 fresh gap PoCs + 1 bonus (not re-reading v462/v463 comments — re-tracing each regex/contextFilter directly) found 6 genuine new misses, all fixed with 6 new rules (1345→1351): (1) DB_LDAP_008 — LDAP filter built via string CONCATENATION ("(&(uid=" + u + ")...") with no request./%s/f-string marker at all (classic textbook shape); DB_LDAP_006/007 both require a source-marker or placeholder syntax neither of which concatenation has. (2) DB_NOSQL_001 — quoted-key Python/JSON form ("$where": "...") wasn't matched; the colon-adjacency check couldn't see past the closing quote of the key string, only the unquoted JS-shorthand form ($where: "...") ever fired. (3) DB_AUTH_ASSERT_003 (new) — assert used via bare equality/dict-lookup (assert u == "admin", assert u.get("role") == "admin") is a third authz-via-assert shape neither ASSERT_001 (attribute form) nor ASSERT_002 (function-call form) covers. (4) DB_MASSASSIGN_011 — hardcoded literal "request." before get_json(); real code sometimes passes Flask's request object under an aliased parameter name (def f(req): data = req.get_json()) — broadened the get_json() branch to match any identifier since that method name is Flask-distinctive regardless of receiver. (5) DB_CRYPTO_FAIL_007 (new) — zero-IV buffer (bytes(16)/bytearray(16)/b"\x00"*N) passed INLINE as the constructor's positional arg (AES.new(key, AES.MODE_CFB, bytes(16))) with no variable assignment at all; DB_CRYPTO_FAIL_006 is anchored on an iv/nonce assignment and can't see this shape. (6) DB_PYTHON_005 — the with-open-as-f two-line context-manager form (with open(path) as f: code = f.read() ... exec(code)) wasn't covered by the single-line var-then-exec branch; added a third alternative tracing the with-block variable through to read() and exec(). All 6 verified via direct regex test: fire on their gap PoC, fire/stay-fired on prior regression cases (unquoted NoSQL, request.get_json, assigned-var IV, inline/var-then-exec Python chains), stay suppressed on corresponding safe-code fixtures (escaped LDAP, allowlisted mass-assign, random IV, unrelated .exec()). DB_PROTOPOLLUTION_006, DB_REDOS_006, DB_CRLF_009_PY, DB_LDAP_007 re-verified firing correctly, unchanged. All 13 <script> blocks syntax-clean via node --check post-edit. v463: 🔍 Recheck of v462's 7 new rules (not re-reading comments — re-tracing each regex/contextFilter against fresh PoCs and adjacent safe code) found 3 real bugs, all fixed: (1) DB_REDOS_006 — contextFilter only checked "is a regex-authoring call anywhere in the ±window", never that the matched text itself looks like a regex, so plain compact arithmetic (e.g. total=(price+tax)+shipping) sitting near an unrelated re.match()/.test() input-validation call false-fired as CRITICAL ReDoS; now also requires a real regex-only signal (backslash escape, character class, dot-quantifier, or alternation) on the matched line. (2) DB_CRYPTO_FAIL_006 — \b(?:iv|...) never matches "_iv" because "_" is a word character, so underscore-prefixed IV variable names (cfb_iv, my_iv) structurally could not match despite cfb_iv being the rule's own worked example in its comment; only bare `iv = ...` ever fired. Fixed to also accept a leading underscore. (3) DB_PYTHON_005 — \bexec\s*\( had no dot-exclusion (matched any .exec() method call — db.exec(), cursor.exec(), unrelated driver APIs) and had zero data-flow tie between the read() and the exec(), so an unrelated open().read() (e.g. reading a config file for logging) within 150 chars of an unrelated exec() call on fixed trusted content false-fired as an "RCE chain". Rewritten to require either the inline exec(open(...).read()) shape or a captured variable from open(...).read() reappearing as exec()'s own argument, with exec not preceded by a dot. All 3 fixes verified via direct regex test: original genuine PoCs (nested-quantifier regex, cfb_iv=bytes(16), open().read()→exec() chain) still fire; all 3 new FP cases (arithmetic-near-regex-call, underscore-prefixed IV miss, unrelated-open-plus-.exec()) no longer fire. DB_LDAP_007 and DB_AUTH_ASSERT_002 re-traced and confirmed correct as-is — no change. All 13 <script> blocks syntax-clean via node --check post-edit. v462: 🎯 8-gap ground-truth diff — traced each rule's actual regex/contextFilter logic (not just re-reading comments) against 8 supplied PoCs. 6 confirmed genuine misses, all fixed: DB_LDAP_007 (filter built via %s/f-string interpolation, no request.* source marker required), DB_AUTH_ASSERT_002 (assert is_admin(user)/assert check_role(user,'admin') function-call form), DB_REDOS_006 (nested-quantifier ReDoS independent of JS slash-delimiter syntax — catches Python re.compile(r'([a-z]+)+')), DB_CRYPTO_FAIL_006 (Python zero-IV idioms b"\x00"*16 / bytes(16)), DB_PROTOPOLLUTION_006 (inverted-logic filter detector, CWE-696), DB_CRLF_009_PY (Flask headers[]/set_cookie() from request.args/values/form). Plus DB_PYTHON_005 (bonus: open(path).read() piped into exec() — unauthenticated RCE chain, CWE-94+CWE-73). NoSQL $where (DB_NOSQL_001) and other flagged shapes re-checked and already fire correctly — left untouched. All 7 new rules verified via isolated regex/contextFilter harness: fire on all 8 gap PoCs verbatim, 0 FP on 7 corresponding safe-code fixtures. All 13 <script> blocks syntax-clean via node --check post-edit. Rule count 1338→1345. v460: 🔧 Missing-rule coverage audit (9 real gaps) — user reported 18 CWE patterns as Never/Miss/Partial detected in real scans. Empirically verified each via a Node VM harness running the real DB{}/runRules() pipeline extracted from this file (not static reading) against synthetic vulnerable + safe fixtures: 10 of 18 (random-in-security-context CWE-338, verify=False CWE-295, NoSQL $where CWE-943, prototype pollution CWE-1321, ReDoS CWE-1333, CRLF CWE-113, static IV CWE-329, weak ciphers CWE-327, os.popen CWE-78, tar slip CWE-22) already fire correctly at the rule-engine level — the user's report likely reflects a downstream cause (STRONG_SANITIZERS suppression, dedup collapse, or a real-world code shape narrower than the rule's contextFilter) rather than a missing rule; flagged for the user to share exact non-firing snippets so that layer can be isolated next. The remaining 9 were genuine, confirmed-empty-result gaps and are now fixed: DB_TLSVERIFY_006 (ssl._create_unverified_context/CERT_NONE — CWE-295, stdlib-level bypass distinct from requests' verify=False), DB_LDAP_006 (LDAP search/bind with filter built as a separate tainted variable 1-2 lines above the sink — CWE-90, the 5 existing LDAP rules only matched same-line literal concatenation), DB_AUTH_ASSERT_001 (assert used for auth/authz checks — CWE-617, stripped entirely under python -O/PYTHONOPTIMIZE), DB_MASSASSIGN_010 (.update(request.json)/.get_json() Flask/SQLAlchemy shape — CWE-915, existing rule only covered the Django update(request.POST) shape), DB_DESERIAL_004 (marshal.loads/jsonpickle.decode/dill.loads/shelve.open with nearby taint — CWE-502, these existed only as SINK_CLASS_MAP categorization labels with zero actual scan rule), DB_PYTHON_INJECTION_004 (getattr(builtins/module, user_input) dynamic dispatch RCE — CWE-95, the file's only dynamic-dispatch detector required a class+dunder-method shape and missed the bare functional-call form), DB_PYTHON_INJECTION_005 (__import__()/importlib.import_module() with user-controlled module name — CWE-95), DB_PYTHON_INJECTION_006/007 (exec()/eval() on a zlib/bz2/lzma-decompressed, marshal-loaded, or base64-decoded payload — CWE-95, both the inline single-call form and the assign-then-execute 2-hop form). All 9 verified via the same harness: fire correctly on vulnerable fixtures, zero false positives on 6 corresponding safe-code fixtures (proper ssl.create_default_context, escaped LDAP filter, non-auth assert, allowlisted update, untainted marshal.loads, fixed-object getattr). All 9 <script> blocks (excluding the 1 pre-existing ES-module block, unrelated) syntax-clean via node --check post-edit. Rule count 1329→1338. v453: 🌍 Framework/language-mismatch fix (Phase 2 continued from v437) — root cause: v437 added python/js/java Before/After variants to FIX_SECTION_MAP for only 7 highest-frequency CWEs (SQLi-89, CmdInj-78, XSS-79, HardcodedCreds-798, SSRF-918, Deser-502, OpenRedirect-601) plus XXE-611, leaving 26 other CWEs always rendering their PHP example even for a Python/JS finding, with only the honesty-note text telling you it was a fallback. Added real python/js Before/After snippets for all 26 remaining structured-fix CWEs: Path Traversal-22, eval/CodeInj-94/95, ShellInj-77, FileInclusion-98, CSRF-352, SessionFixation-384, InsecureLogout-613, MissingSecureCookie-614, BruteForce-307, WeakCrypto-327, WeakPasswordHash-328/916, WeakPRNG-338, FileUpload-434, CRLF-113, ErrorDisclosure-209, SensitiveLogs-532, MissingAuthZ-285, MissingAuthN-287, IDOR-639, MassAssignment-915, TOCTOU-367, RaceCondition-362, IntegerOverflow-190, NoSQLi-943 (python/pymongo added; js was already native). CWE-1321 (Prototype Pollution) intentionally left PHP/Java-variant-free — it's a JS/Node-prototype-chain-specific bug class with no equivalent PHP/Python idiom. SECOND BUG FOUND DURING VERIFICATION: buildFixSection()'s fallback language was hardcoded to the literal 'php', which silently mislabeled CWE-943 and CWE-1321 as "PHP-pattern reference" (isFallback:true, lang:'php') even when the requesting language was 'js' — because their base Before/After template was ALREADY js, not php, but the function had no way to know that. Fixed by adding a per-entry `baseLang` field (defaults to 'php' for every other entry, so the other 33 CWEs are byte-for-byte unchanged) and comparing reqLang against data.baseLang instead of a hardcoded string; the honesty-note text now also names the real base language instead of always saying "PHP-pattern reference". Verified via a Node harness evaluating the live buildFixSection()/FIX_SECTION_MAP source extracted from this file (not a rewritten copy): all 26 newly-added CWEs resolve isFallback:false for both python and js; CWE-943/1321 correctly resolve isFallback:false for js post-fix (were incorrectly true before); an unmapped language (e.g. ruby) still correctly falls back and now names the right base language in the note; the 8 CWEs already covered by v437 and the DEFAULT case are unchanged. All 13 <script> blocks syntax-clean via node --check after the edit — zero detection-logic changes, only FIX_SECTION_MAP content and the fallback-language lookup were touched. v452: 🎯 Line-mapping audit fix (v449 Hardcore Test #3 report) — root cause confirmed as 3 separate whole-file detectors that never converted a regex match position into a real line number: (1) detectAdvancedCrypto() (Weak Hash/Weak Random/ECB/Hardcoded IV) used .test()/.match() and discarded match.index entirely, so `.line` was always undefined — fixed by switching to .exec() (which exposes match.index) and computing the real 1-based line via code.slice(0,idx).split('\n').length, same convention already used elsewhere in the file. (2) detectHighEntropySecrets() used code.match(/g) which returns matched text only, no positions — fixed by switching to a regex.exec() loop, which does expose .index per match. (3) detectMissingSecurityHeadersV31() (CSP/HSTS/X-Frame-Options/NoSniff/Referrer-Policy + aggregate) hardcoded `line: 0` for all 6 findings — these are genuinely whole-app absence findings with no single vulnerable line, so instead of faking a number, anchored them to the real line where the Express app is initialized (require('express')/app=express()/app.listen/app.use) and added an explicit "[File-level check...]" note to the description so the report doesn't misrepresent an absence-of-header finding as a specific-line bug. All 3 root causes fed the same downstream `line: r.line || 1` merge-loop fallback in the v442 wiring block, which is exactly why every one of them surfaced as L1 in the report regardless of where the real match was. Verified by extracting the 3 functions into an isolated Node harness (not just static reading) and running them against synthetic multi-line fixtures: Weak Hash MD5 on line 9 → reported line 9 (was L1); high-entropy secret on line 9 → reported line 9 (was L1); Math.random() security-context on line 4 → reported line 4; ECB/hardcoded-IV on lines 10-11 → reported lines 10/11; missing-security-headers on a 3-line Express app → all 6 findings anchored to line 2 (the require('express') line) instead of the old fake line 0. All 13 <script> blocks syntax-clean via node --check after the edit — zero regression risk, since only the `.line` field computation changed, not any detection/matching logic. v449: 🔧 IDOR _HRE_RULES wiring audit — same class of gap as v438's HRE_XXE_06/07 finding: HRE_IDOR_01/02/03 live ONLY in _HRE_RULES (CyberHybridEngine.scan(), Stage 3.5-only), never reachable from runRules()/the benchmark. Confirmed functionally covered by properly-wired duplicates already in runRules() (DB_AUTH_009/065/010) — full 510-fixture Node VM harness re-run before/after (runRules()→runV11DeepScan()→postProcessResults()) showed 0 bucket changes across all 35 categories (TP:315 FP:3 FN:8 TN:184, byte-identical), IDOR itself unchanged at TP:5 FP:0 FN:0 TN:3 = 100% both before and after. Left unwired rather than merged into runRules() to avoid double-counting the same finding through two parallel engines. Also fixed a real (if currently dormant) bug found during the audit: HRE_IDOR_02's contextFilter required a literal "request." or "req." (with a dot) in its ±20-line window to confirm a request-handler context — but a Django view signature is `def get_document(request, pk):`, where "request" appears only as a bare parameter name (comma after it, never a dot), so the filter silently dropped the textbook-vulnerable fixture whenever CyberHybridEngine.scan() ran it directly. Loosened to accept the bare word too. Added cross-reference comments on all three HRE_IDOR_* rules pointing to their runRules() counterparts, matching the v438 precedent. Verified: all 9 <script> blocks syntax-clean via node --check, rule-ID count unchanged (1312 unique IDs, 3 HRE_IDOR_* rules) before and after. v448: 🎯 PHAR/INDIA_DPDP benchmarks fixed to 100% — root cause in both was the SAME class of bug the v447 pathinfo fix closed for FILE_UPLOAD: the STRONG_SANITIZERS global choke-point in postProcessResults() treats "any known-safe pattern nearby" as blanket suppression, but a sanitizer that's genuinely safe for ONE vuln class can be irrelevant or actively wrong for another on the SAME line. PHAR 85%→100% (TP:12 FP:0 FN:0 TN:1): basename()/pathinfo() correctly stay in PHP_SAN for PATH_TRAVERSAL (they strip directory components) but do NOT strip a phar:// stream wrapper — PHAR-005's own contextFilter already encodes "basename() alone is NOT safe", yet the later global pass silently overruled that correct per-rule decision on the strength of the word "basename" alone, missing TP-PH9 ($file=basename($_GET[f]); file_exists('/uploads/'.$file)) and TP-PH10 (identical shape via getimagesize()). INDIA_DPDP 89%→100% (TP:6 FP:0 FN:0 TN:3): a real PAN card stored via $pdo->prepare("INSERT INTO kyc SET pan=?")->execute([$pan]) with zero encryption was being suppressed because ->prepare()/->bindParam() sit in PHP_SAN as legitimate SQL-injection sanitizers — but a parameterized query protects the QUERY from injection, not the DATA from plaintext exposure; the DPDP violation is orthogonal to SQLi and the generic gate couldn't tell the two apart. Fixed by giving both finding families (PHAR-*/DB_PHARDESER_* by rule id; DB_INDIA_DPDPA_*/DB_PII_* by rule id or CWE-312/CWE-359) their own narrow safe-evidence check instead of the shared STRONG_SANITIZERS regex — PHAR now requires an explicit wrapper block (preg_match/strpos/str_starts_with mentioning phar, or a literal phar:// check) in the window; PII now requires genuine data protection (openssl_encrypt/hash/bcrypt/argon2/masking/redaction). Every other rule keeps the original unchanged global gate. Verified against the full PHAR (13 fixtures) and INDIA_DPDP (9 fixtures) suites by hand-tracing each rule's regex + contextFilter + the new suppression branch: the two previously-safe PHAR fixtures (basename+realpath+phar-preg_match; basename-only for PATH_TRAVERSAL, a different rule id so unaffected) and the two previously-safe PII fixtures (masked UPI via .replace() "mask" label; PAN via openssl_encrypt) all still correctly suppress under the new narrower checks — no regression to the existing 100% PATH_TRAVERSAL/FILE_UPLOAD/DESER benchmarks, which don't touch either new branch. v447: 🎯 FILE_UPLOAD/DESER benchmarks fixed to 100% — FILE_UPLOAD: root cause was the STRONG_SANITIZERS global choke-point (postProcessResults()'s "any known-safe pattern nearby" gate) including bare pathinfo() in PHP_SAN — pathinfo()/PATHINFO_EXTENSION only extracts the extension string, it performs zero validation, but its mere presence silently dropped every finding in-window, including the classic extension-only-allowlist bypass ($ext === 'jpg' then move_uploaded_file with no MIME check — the exact shell.php.jpg double-extension pattern this codebase's own DB_UPLOAD_001/PHAR rules already document). Removed pathinfo from PHP_SAN (realpath/basename kept — those two do real containment work) and added DB_FILE_UPLOAD_009 (extension-check-without-MIME/rename detector) as defense in depth. DESER: found FOUR separate pickle.loads()/pickle.load() rules (DB_XSS_030, DB_CRYPTO_009, DB_DESERIALPLUS_004, DB_DESER_ADVANCED_002) each flagging unconditionally or on a bogus taint signal — DB_XSS_030's contextFilter returned true on BOTH branches (dead-code gate), DB_CRYPTO_009 had no contextFilter at all, DB_DESERIALPLUS_004 likewise, and DB_DESER_ADVANCED_002's own regex treated bare .read() inside the call args as "user data" evidence, so pickle.loads(f.read()) flagged even when f was opened from a hardcoded literal path with zero external input. All four now share one real taint-evidence gate (request./req.body/socket/argv/environ/superglobals — comments stripped first so phrases like "no user input" can't fake taint) matching the one correct rule (DESER-002) that already existed. Verified via a Node VM harness re-running the exact runRules()→runV11DeepScan()→postProcessResults() benchmark pipeline: FILE_UPLOAD 83%→100% (TP:3 FP:0 FN:0 TN:3), DESER 91%→100% (TP:7 FP:0 FN:0 TN:4), and a full PATH_TRAVERSAL/PHAR/LFI regression pass confirmed zero new failures from the pathinfo removal (PHAR's 2 pre-existing TP-PH9/TP-PH10 misses — basename()-alone-doesn't-block-phar:// — were already failing before this change and are unrelated to it, left untouched). v446: 🔧 Sanitizer-engine cross-language suppression fix — root cause: STRONG_SANITIZERS (the single global "is any known-safe pattern present nearby" gate inside postProcessResults()) was split into per-language pattern banks (PHP_SAN/JS_SAN/PY_SAN/JAVA_SAN/GO_SAN/RUBY_SAN) and restricted to ONLY the whole-file's detected language, so a sanitizer belonging to a DIFFERENT language embedded in the same file became invisible — most commonly a PHP/Python/Java file that echoes an inline <script> block using DOMPurify.sanitize()/textContent (JS_SAN), which stopped suppressing the instant the file's overall language wasn't classified 'js'. Reproduced directly against a 10-pattern all-safe PHP test fixture (Grade A/93+ before the split, Grade F/1 after) — the DOMPurify+textContent case (Script Block with User Input, CWE-79) was the exact new false positive. Fixed by making STRONG_SANITIZERS always match the FULL UNION of every language's pattern bank (STRONG_SANITIZERS_ALL) instead of gating on detected language — restores v443's language-agnostic behavior for this one global gate while keeping the expanded per-language coverage as the union's source. Also closed two smaller PHP_SAN gaps caught by the same fixture: in_array() (PHP allowlist guard, used for LFI/MIME allowlisting) and the mysqli OOP-style ->bind_param() call (only the procedural mysqli_stmt_bind_param() and PDO's camelCase ->bindParam() were present, missing the equally common underscore OOP form). Verified: all 13 <script> blocks syntax-clean via node --check after the edit. v445: 🔧 Restored 7 per-detector FP-suppression guards (AdvancedCMD execve-array-arg exception, AdvancedSQLi SQL-keyword+intval gate, HighEntropySecrets SRI-hash exemption, OpenRedirectAdvanced/DFSTaintedSinks allowlist-guard exemption, SecondOrderInjection request-input-evidence gate, MissingSecurityHeadersV31 server-code gate, detectJWTIssue PyJWT algorithms= gate, detectSSRFInternalStrict hardcoded-localhost gate) that v443's rewrite of the detector-wiring block silently dropped — found via diff against the archived v442 build. Also restored the RATE_LIMIT/INFO_DISC/CORS entries in ACC_CAT_CWE_FAMILY (benchmark-scoring only) that the same rewrite dropped. All 7 guards scoped to their original detector tag only — every other detector keeps v443's unconditional call. v444: 🌍 World-class multi-file scan fix — root cause: a live GitHub repo scan of OWASP-BenchmarkPython (2,740 files / 124,837 lines) returned only 3 total findings. Two causes: (1) runRules()/CyberHybridEngine.scan() received the literal filename 'combined' for any multi-file scan — shouldScan()'s extension-allowlist check (R7) rejects a filename with no extension, so isTestFile('combined') was always true and runRules() — the main 1329-rule engine — silently returned [] for EVERY multi-file scan; the benchmark's 3 survivors came only from runAdvancedEngine() (no filename param). (2) every dedup/bucketing layer downstream (XSS same-line collapse, v225 CWE+line-bucket reconciliation, DedupEngine.buildKey()'s 10-line proximity window, makeFingerprint, VarSink) keys purely off finding.line with no file-boundary awareness — findings from different files landing in the same window silently merged into one card. Fix: Stage 3 (runRules+runAdvancedEngine), Stage 3.5 (CyberHybridEngine), and Stage 4.5 (AST engine) now run PER FILE for multi-file scans, each with its own real filename (fixing #1) and a 1,000,000-line-per-file offset applied to results before merging (fixing #2 — makes cross-file dedup collisions structurally impossible). Every finding also gets a .sourceFile tag. Single-file scans are byte-for-byte unchanged (zero regression risk). Stage 4.6 XFTE (already realScans-aware) untouched. Verified via node --check across all 10 script blocks (0 new errors vs. the 1 pre-existing ES-module parse quirk already present in the unmodified v443 build) — full runtime re-verification pending a live re-run of the OWASP Benchmark scan (browser-globals-heavy pipeline can't run in a Node harness, per established practice for this file). v443: 🆕 GitHub Repo Scan — added "All files" option to the MAX FILES selector (was capped at 10/20/50/100). The dropdown's 'all' value is converted to Infinity before being passed into fetchRepoFiles(), so the existing scannable.slice(0, maxFiles) line naturally returns every scannable file in the repo with zero new branching logic. Audited every reference to gh-max-files/maxFiles across the file (scan-trigger handler, fetchRepoFiles signature, the slice call itself) — single select element, single read site, single consumer, no duplicates or stale copies. Confirmed all displayed counts (scans.length, totalFound, skipped.length) stay real finite numbers since Infinity only ever bounds the slice, never reaches the UI. Also caught and fixed a pre-existing stale header badge that still read v441 while the title/report already said v442. v442: 🔧 Grade-A Safe-Code FP Fix — root cause: 1329 rules across many independent engines each had their own ad-hoc (or absent) sanitizer contextFilter, so a real sanitizer/allowlist call sitting right next to a tainted sink still let unrelated rules fire ($_GET seen → VULN, regardless of guards). Fixed with one global choke-point pass inside postProcessResults(), after every engine's output converges into finalResult: a STRONG_SANITIZERS check (escapeshellarg, htmlspecialchars, DOMPurify.sanitize, realpath, basename, finfo, is_numeric, hash_equals, preg_match, random_bytes, textContent, allowed_classes) scans a ±5/±6 line window around each finding's line(s); a match drops the finding entirely (spliced out, not just score-discounted). Two bugs caught during verification: (1) first draft reassigned the const finalResult via .filter(), which silently threw "Assignment to constant variable" into the outer catch and skipped the whole pass — fixed by filtering in place via reverse-indexed splice; (2) startScan()'s STAGE 8 has a pre-existing emergency fallback that reconstructs raw pre-filter findings whenever all findings collapse to zero — this would have silently undone the v442 suppression on exactly the all-safe-file case it targets, so postProcessResults() now stamps a _v442SuppressedCount expando on the returned array and the fallback only fires when that count is 0 (genuinely unexplained zero, not intentional suppression). Verified via a Node VM harness running the real runRules()→postProcessResults() pipeline: 10 synthetic safe-code fixtures (one per sanitizer above) → 0 surviving findings (was 100% FP); raw vulnerable code with no sanitizer (SQLi/RCE/object-injection/XSS) still detected correctly, zero regression; all 13 <script> blocks syntax-clean via node --check. v441: 🔧 C/C++ severity-burial fix — root cause: memory-corruption CWEs (CWE-120 strcpy/gets, CWE-134 printf format-string, CWE-416 UAF, CWE-415 double-free) returned null from the vulnClass() classifier, so the ENTIRE SevEngine v3 family-floor block was skipped for them — no _sevV3Score, no reason trace, and a real strcpy() buffer overflow silently fell from rule-declared CRITICAL to MEDIUM/45% confidence with zero visibility in the report. Fixed by adding two new floor classes: MemoryCorruptionCritical (CWE-120/134/416/415 → CRITICAL floor, same as RCE/SQLi) and MemoryCorruptionHigh (CWE-121 VLA / CWE-122 memcpy-unvalidated, rule-declared HIGH → HIGH floor only, not force-upgraded to CRITICAL). Also fixed DB_C_CPP_SEC_004 (CWE-134 format-string rule): old regex only matched a hardcoded variable-name allowlist (argv[/getenv/buf/input/user/param), so printf(name)/printf(msg)/printf(str) with any other identifier were silently missed even though the whole point of format-string injection is that ANY non-literal sole argument is unsafe; broadened to match any bare identifier as the sole argument while preserving the existing argv[/getenv(...) call-pattern matches (verified no regression via direct regex A/B test on both old-pattern and new-pattern cases). Also fixed the global hasDirectUserInput/hasIndirectUserInput taint-source detector: it only recognized PHP/JS web-request sources ($_GET, req.body, location.search) — C/C++ source code could never match, so every C/C++ finding permanently lost the +10/+6/+3 tiered confidence boost regardless of how exploitable it was; added C-native sources (argv[, getenv(), scanf/fscanf/sscanf/gets, fgets(...,stdin)). Verified: all 3 fixes syntax-checked via Node `new Function()` parse of every <script> block (0 new errors vs. baseline), plus direct regex/logic unit tests confirming both the new detections work and the two previously-working patterns (printf(argv[1]), printf(getenv(...))) still match after a first-draft regression was caught and corrected during recheck. v439: 🔧 Phase 3 (JWT Deduplication) — root cause: CWE-347 was completely absent from CWE_FAMILY_MAP (normalizeCWE returned the raw 'CWE-347' string as its own "family"), and no jwt.*() pattern existed in SINK_CLASS_MAP/SINK_NORM_MAP, so DedupEngine.buildKey() fell to its generic "CWE + exact line" fallback with sinkClass always null — two rule-engine findings for the SAME jwt.verify()/jwt.decode() call (e.g. "algorithms:['none']" and "decoded without signature verification") landed on different exact lines when the call spans multiple lines (options object below the call) and never collided into one card. Fix: mapped CWE-347 → new JWT_AUTH family, added jwt.decode/verify/sign + JWT::decode + jwt_decode() + Jwts.parser() patterns to both SINK_CLASS_MAP (buildKey) and SINK_NORM_MAP (makeFingerprint, kept in sync per the v299/v338 convention), and added JWT_AUTH to both HIGH_SEV_FAMILIES and HIGH_FP_FAMILIES so JWT findings get the same ±10-line proximity-window treatment as RCE_EVAL/CMD_EXEC/SQLI/etc. Verified two ways: (1) direct DedupEngine.buildKey() A/B test on the exact reported scenario — before: CWE-347__L12 vs CWE-347__L13 (2 separate cards); after: JWT_AUTH__jwt_auth__W10 for both (1 merged card) — while a sanity case with two genuinely distinct jwt calls >10 lines apart correctly stayed 2 cards; (2) full Node VM harness re-run of all 510 benchmark fixtures via the actual runRules()→runV11DeepScan()→postProcessResults() pipeline — zero bucket changes (TP:316 FP:4 FN:7 TN:183, identical to pre-fix and to the v437 baseline; JWT category itself unchanged at TP:4 FP:0 FN:0 TN:2 since none of the 6 JWT benchmark fixtures happen to trigger the multi-line-call duplicate — the gap only shows on real-world code where the sink call spans lines, exactly as originally reported). v438: 🔍 Phase 1 (False-Positive-Killer wiring audit) — grep+call-graph audit of 4 claimed-implemented items confirmed 3/4 actually wired into runRules(): SV.isSanitized() sanitizer registry (confirmed reachable via isSanitized()/isSanitizedContext() wrappers + TaintAnalyzer), isInternalURL()/isInternalSSRFContext() RFC1918/loopback checks (confirmed called), and DB_RATE_LIMIT_00x rate-limit rules (confirmed direct DB entries, always in runRules()). Found + fixed: SecurityValidator.isFullyMitigated() (SSRF allowlist+internal-block gate) was DEAD CODE — defined, zero callers anywhere in the file (same class of gap as the v402 SSRF / v414 CSRF / v432 MASS_ASSIGN wiring bugs) — removed rather than wired in, since its logic is a strict subset of checkSSRF()'s already-wired hasSufficientSSRFBlock tiering. Also found: HRE_XXE_06/07 (lxml + stdlib ET rules) live only in _HRE_RULES (CyberHybridEngine.scan()-only, NOT merged into runRules()) — functionally covered for benchmark/production via a separate duplicate pair, XXE-B06/B07 in RUDRA_EXTRA_RULES.xxe, which IS merged into runRules() at the v391 wiring block — added explicit cross-reference comments on both pairs so future tuning doesn't silently diverge between full-scan and benchmark accuracy. No regex/contextFilter/detection logic changed — zero benchmark bucket risk; verified by re-parsing every <script> block post-edit (same 1 pre-existing ES-module parse skip as the unmodified file, 0 new syntax errors). v437: 🔧 Phase 2 (Framework/Language Awareness) — fixed detectPHPSessionFixation()'s django_session_write case silently falling back to the PHP session_regenerate_id() fix/description (fixMap['django']/descMap['django'] were missing entirely — fixMap[bLang]||fixMap.php defaulted every Django finding to PHP) — added a real Django cycle_key() fix+description. Also fixed buildFixSection()/FIX_SECTION_MAP: the structured Before/After template card was ALWAYS PHP regardless of the finding's actual language — added python/js/java variants for the 7 highest-frequency CWEs (SQLi-89, CmdInj-78, XSS-79, HardcodedCreds-798, SSRF-918, OpenRedirect-601, Deserialization-502, XXE-611), wired the detected language into buildFixSection(), and made the TEMPLATE GUIDE banner honestly flag PHP-fallback cases instead of silently mislabeling PHP code as a "generic pattern" for every language. Verified via the Node VM harness across all 510 benchmark fixtures — zero bucket changes (TP:316 FP:4 FN:7 TN:183, identical before/after), confirming no detection-logic side effects since only the remediation/fix-text layer was touched. v432: 🔧 INFRA/RATE_LIMIT/MASS_ASSIGN benchmarks fixed to 100% — INFRA 67%→100% (TP:4 FP:0 FN:0 TN:2): DB_CICD_002's CI/CD hardcoded-secret regex matched the literal YAML field name "key: password" inside a K8s secretKeyRef reference (not a real secret) — added a contextFilter skipping valueFrom/secretKeyRef/secretRef context; DB_SUPPLY_CHAIN_016 correctly flagged the test's own unpinned "FROM node:18-alpine" as a genuine, separate CWE-829 finding unrelated to the "runs as root" concept being isolated — fixed the benchmark fixture itself by pinning to @sha256 digest. RATE_LIMIT 75%→100% (TP:2 FP:0 FN:0 TN:2): DB_APISEC_002 flagged every /login route lacking a hand-rolled attempts[] object even when express-rate-limit middleware was already applied — extended its contextFilter to recognize limiter/rateLimit(/slowDown( as a real mitigation. MASS_ASSIGN 75%→100% (TP:2 FP:0 FN:0 TN:2): two-part bug — detectPythonMassAssignment()'s source alternation was missing Django's request.POST (had only json/get_json()/form/values), AND the whole detector lived only inside runAdvancedEngine() (interactive scan path), never wired into runRules() — same class of gap as the v402 SSRF and v414 CSRF fixes — so even a correct regex would still miss in the benchmark; fixed the regex and wired the detector directly into runRules(). Verified via a real Node VM harness executing the actual runRules()→runV11DeepScan()→postProcessResults() pipeline against all 510 benchmark fixtures, case-by-case before/after diff — exactly 4 cases changed, zero regressions elsewhere. | v431: 🔧 JWT benchmark fixed 67%→100% (TP:4 FP:0 FN:0 TN:2) — DB_XSS_023's regex used a 3-way alternation where the process.env requirement only applied to an unreachable 3rd branch, so bare jwt.sign()/jwt.verify() matched unconditionally — false-fired on the textbook-safe jwt.verify(token, process.env.JWT_SECRET, {algorithms:[...]}); narrowed to the actually-risky process.env.X || 'literal-fallback' shape. DB_AUTH_042 and its duplicate DB_ACCESS_CONTROL_004 were language-blind: they treated jwt.decode() as always-unverified, true for Node's jsonwebtoken but false-fired on PyJWT's jwt.decode(token, key, algorithms=[...]) which DOES verify the signature in Python — added a contextFilter recognizing decode() with a real key arg (and no verify_signature=False) as safe. Bonus: DB_XSS_023's bug was also hitting the AUTH category (90%→100%). Verified via live pipeline execution across all 510 benchmark fixtures — zero regressions elsewhere. | v430: 🎯 PATH_TRAVERSAL benchmark ACTUALLY fixed 75%→100% (TP:5 FP:0 FN:0 TN:3) — v429's checkPathTraversal() taint-tracking rewrite was correct but didn't move the score because the 2 remaining FPs were coming from completely different, unrelated rules that the benchmark still counts against the PATH_TRAVERSAL bucket (it counts ANY surviving finding for a fixture, regardless of which rule/category fired): (1) PHAR-005 fired on the PHP basename()+realpath()+strpos() safe fixture because its contextFilter only recognized phar-labeled sanitization, not the generic realpath()+strpos() base-dir containment jail that structurally blocks phar:// too — widened the exemption; (2) DB_FILE_UPLOAD_005 fired on the Express ALLOWED-allowlist safe fixture because its pattern matched the bare word "upload" with no word boundary, so it false-matched the substring inside the ordinary "/uploads/" directory path — narrowed the pattern to real upload-object references (req.file, req.files, uploadedFile, etc.) and added a contextFilter for existing safe headers/allowlists. Bonus: found + fixed the same root cause in the 502-PHAR-DESERIALIZATION file_exists() rule (contextFilter only checked "is $_GET mentioned nearby" instead of "was it actually validated" — ignored a full realpath+strpos+preg_match guard) — PHAR category benchmark also now 100% (was 92%, pre-existing, unrelated to v429's claim) as a side effect, verified via live pipeline execution (extracted all engine JS, ran under Node against the exact benchmark fixtures) rather than static code reading, since this file has multiple overlapping/duplicate rule arrays with the same IDs that make static tracing unreliable. | v425: 🧠 CONTEXT AI ENGINE — world-class rewrite: context() flags 7→13 (added network/SSRF, template/SSTI, crypto, redirect, nosql, xxe — 'NETWORK' bucket existed since v180 but was unreachable dead code, no flag ever set it) · taint() is now whole-file variable-level via trackVariables() dataflow graph instead of only a ±10 line window (catches sources >13 lines from the sink — same miss class checkLFI had to route around separately) · san() is now sink-aware — a sanitizer only counts for the vuln class it actually mitigates (escapeshellarg no longer suppresses XSS, htmlspecialchars no longer suppresses SQLi) · aiScore() now actually consumes san (previously computed and discarded — STRONG prepared-statement sanitization had zero effect on score) · scanAll() gained SSRF/SSTI/NOSQLI/XXE/OPEN_REDIRECT + explicit severity-ordered priority (was silently last-match-wins) · RECHECK FIXES: WEAK_CRYPTO had no aiScore() base-score entry (silently fell to generic 50) and no dedicated sanitizer table — added; san discount is now a separate post-clamp stage instead of folded into the same multiplier as input/taint — the old design meant any line matching BOTH ctx.input and taint on the same line (e.g. unserialize($_GET[x])) pre-saturated past 100, so a STRONG sanitizer (e.g. json_decode next to it) had zero visible effect on score/severity, caught via an I1-vs-I2 differential test | v421-v422: 🔧 SUPPLY_CHAIN benchmark fixes — curl/wget-piped-to-shell FN root cause fixed (unquoted "://" was mistaken for a comment start, truncating the payload before the pipe-to-shell evidence) · SC-10 CDN-SRI FN fixed (corrupted test fixtures — " 🔍 Phase 1 (False-Positive-Killer wiring audit) — grep+call-graph audit of 4 claimed-implemented items confirmed 3/4 actually wired into runRules(): SV.isSanitized() sanitizer registry (confirmed reachable via isSanitized()/isSanitizedContext() wrappers + TaintAnalyzer), isInternalURL()/isInternalSSRFContext() RFC1918/loopback checks (confirmed called), and DB_RATE_LIMIT_00x rate-limit rules (confirmed direct DB entries, always in runRules()). Found + fixed: SecurityValidator.isFullyMitigated() (SSRF allowlist+internal-block gate) was DEAD CODE — defined, zero callers anywhere in the file (same class of gap as the v402 SSRF / v414 CSRF / v432 MASS_ASSIGN wiring bugs) — removed rather than wired in, since its logic is a strict subset of checkSSRF()'s already-wired hasSufficientSSRFBlock tiering. Also found: HRE_XXE_06/07 (lxml + stdlib ET rules) live only in _HRE_RULES (CyberHybridEngine.scan()-only, NOT merged into runRules()) — functionally covered for benchmark/production via a separate duplicate pair, XXE-B06/B07 in RUDRA_EXTRA_RULES.xxe, which IS merged into runRules() at the v391 wiring block — added explicit cross-reference comments on both pairs so future tuning doesn't silently diverge between full-scan and benchmark accuracy. No regex/contextFilter/detection logic changed — zero benchmark bucket risk; verified by re-parsing every <script> block post-edit (same 1 pre-existing ES-module parse skip as the unmodified file, 0 new syntax errors). v437: 🔧 Phase 2 (Framework/Language Awareness) — fixed detectPHPSessionFixation()'s django_session_write case silently falling back to the PHP session_regenerate_id() fix/description (fixMap['django']/descMap['django'] were missing entirely — fixMap[bLang]||fixMap.php defaulted every Django finding to PHP) — added a real Django cycle_key() fix+description. Also fixed buildFixSection()/FIX_SECTION_MAP: the structured Before/After template card was ALWAYS PHP regardless of the finding's actual language — added python/js/java variants for the 7 highest-frequency CWEs (SQLi-89, CmdInj-78, XSS-79, HardcodedCreds-798, SSRF-918, OpenRedirect-601, Deserialization-502, XXE-611), wired the detected language into buildFixSection(), and made the TEMPLATE GUIDE banner honestly flag PHP-fallback cases instead of silently mislabeling PHP code as a "generic pattern" for every language. Verified via the Node VM harness across all 510 benchmark fixtures — zero bucket changes (TP:316 FP:4 FN:7 TN:183, identical before/after), confirming no detection-logic side effects since only the remediation/fix-text layer was touched. v432: 🔧 INFRA/RATE_LIMIT/MASS_ASSIGN benchmarks fixed to 100% — INFRA 67%→100% (TP:4 FP:0 FN:0 TN:2): DB_CICD_002's CI/CD hardcoded-secret regex matched the literal YAML field name "key: password" inside a K8s secretKeyRef reference (not a real secret) — added a contextFilter skipping valueFrom/secretKeyRef/secretRef context; DB_SUPPLY_CHAIN_016 correctly flagged the test's own unpinned "FROM node:18-alpine" as a genuine, separate CWE-829 finding unrelated to the "runs as root" concept being isolated — fixed the benchmark fixture itself by pinning to @sha256 digest. RATE_LIMIT 75%→100% (TP:2 FP:0 FN:0 TN:2): DB_APISEC_002 flagged every /login route lacking a hand-rolled attempts[] object even when express-rate-limit middleware was already applied — extended its contextFilter to recognize limiter/rateLimit(/slowDown( as a real mitigation. MASS_ASSIGN 75%→100% (TP:2 FP:0 FN:0 TN:2): two-part bug — detectPythonMassAssignment()'s source alternation was missing Django's request.POST (had only json/get_json()/form/values), AND the whole detector lived only inside runAdvancedEngine() (interactive scan path), never wired into runRules() — same class of gap as the v402 SSRF and v414 CSRF fixes — so even a correct regex would still miss in the benchmark; fixed the regex and wired the detector directly into runRules(). Verified via a real Node VM harness executing the actual runRules()→runV11DeepScan()→postProcessResults() pipeline against all 510 benchmark fixtures, case-by-case before/after diff — exactly 4 cases changed, zero regressions elsewhere. | v431: 🔧 JWT benchmark fixed 67%→100% (TP:4 FP:0 FN:0 TN:2) — DB_XSS_023's regex used a 3-way alternation where the process.env requirement only applied to an unreachable 3rd branch, so bare jwt.sign()/jwt.verify() matched unconditionally — false-fired on the textbook-safe jwt.verify(token, process.env.JWT_SECRET, {algorithms:[...]}); narrowed to the actually-risky process.env.X || 'literal-fallback' shape. DB_AUTH_042 and its duplicate DB_ACCESS_CONTROL_004 were language-blind: they treated jwt.decode() as always-unverified, true for Node's jsonwebtoken but false-fired on PyJWT's jwt.decode(token, key, algorithms=[...]) which DOES verify the signature in Python — added a contextFilter recognizing decode() with a real key arg (and no verify_signature=False) as safe. Bonus: DB_XSS_023's bug was also hitting the AUTH category (90%→100%). Verified via live pipeline execution across all 510 benchmark fixtures — zero regressions elsewhere. | v430: 🎯 PATH_TRAVERSAL benchmark ACTUALLY fixed 75%→100% (TP:5 FP:0 FN:0 TN:3) — v429's checkPathTraversal() taint-tracking rewrite was correct but didn't move the score because the 2 remaining FPs were coming from completely different, unrelated rules that the benchmark still counts against the PATH_TRAVERSAL bucket (it counts ANY surviving finding for a fixture, regardless of which rule/category fired): (1) PHAR-005 fired on the PHP basename()+realpath()+strpos() safe fixture because its contextFilter only recognized phar-labeled sanitization, not the generic realpath()+strpos() base-dir containment jail that structurally blocks phar:// too — widened the exemption; (2) DB_FILE_UPLOAD_005 fired on the Express ALLOWED-allowlist safe fixture because its pattern matched the bare word "upload" with no word boundary, so it false-matched the substring inside the ordinary "/uploads/" directory path — narrowed the pattern to real upload-object references (req.file, req.files, uploadedFile, etc.) and added a contextFilter for existing safe headers/allowlists. Bonus: found + fixed the same root cause in the 502-PHAR-DESERIALIZATION file_exists() rule (contextFilter only checked "is $_GET mentioned nearby" instead of "was it actually validated" — ignored a full realpath+strpos+preg_match guard) — PHAR category benchmark also now 100% (was 92%, pre-existing, unrelated to v429's claim) as a side effect, verified via live pipeline execution (extracted all engine JS, ran under Node against the exact benchmark fixtures) rather than static code reading, since this file has multiple overlapping/duplicate rule arrays with the same IDs that make static tracing unreliable. | v425: 🧠 CONTEXT AI ENGINE — world-class rewrite: context() flags 7→13 (added network/SSRF, template/SSTI, crypto, redirect, nosql, xxe — 'NETWORK' bucket existed since v180 but was unreachable dead code, no flag ever set it) · taint() is now whole-file variable-level via trackVariables() dataflow graph instead of only a ±10 line window (catches sources >13 lines from the sink — same miss class checkLFI had to route around separately) · san() is now sink-aware — a sanitizer only counts for the vuln class it actually mitigates (escapeshellarg no longer suppresses XSS, htmlspecialchars no longer suppresses SQLi) · aiScore() now actually consumes san (previously computed and discarded — STRONG prepared-statement sanitization had zero effect on score) · scanAll() gained SSRF/SSTI/NOSQLI/XXE/OPEN_REDIRECT + explicit severity-ordered priority (was silently last-match-wins) · RECHECK FIXES: WEAK_CRYPTO had no aiScore() base-score entry (silently fell to generic 50) and no dedicated sanitizer table — added; san discount is now a separate post-clamp stage instead of folded into the same multiplier as input/taint — the old design meant any line matching BOTH ctx.input and taint on the same line (e.g. unserialize($_GET[x])) pre-saturated past 100, so a STRONG sanitizer (e.g. json_decode next to it) had zero visible effect on score/severity, caught via an I1-vs-I2 differential test | v421-v422: 🔧 SUPPLY_CHAIN benchmark fixes — curl/wget-piped-to-shell FN root cause fixed (unquoted "://" was mistaken for a comment start, truncating the payload before the pipe-to-shell evidence) · SC-10 CDN-SRI FN fixed (corrupted test fixtures — "
// RUDRA v472 — 9-Stage Pipeline · 1338 Rules · PHP/JS/Python/Java/Go/C++ · Framework Taint Engine · PHP/JS/Python/Java/Go/C++/Android · India Compliance (DPDPA 2023)
0 lines · 0 chars
✓ Auto-detect active
GITHUB URL — FILE OR REPO:
MAX FILES:
BRANCH:
✅ SUPPORTED:
github.com/user/repo — 🆕 Full repo scan (src/, config/, routes/...)
github.com/user/repo/blob/branch/file.php — Single file
raw.githubusercontent.com/user/repo/branch/file.py
gist.github.com/gist_id
📁
DROP FILES HERE
or click to browse — multiple files OK
.php .js / .ts .py .java .html .cpp / .c .env .json / .yml .sql .zip 📦 full extract .apk 📱 string scan
INITIALIZING...
SCANNING... 0%
◌ Load ◌ Pattern Match ◌ Vuln Check ◌ Risk Score ◌ Report
🤖 OpenAI fine-tune
🤗 HuggingFace datasets
🦥 Unsloth/LoRA Alpaca
📦 Raw current
🧠
AI TRAINING DASHBOARD
Pehle code scan karo — training dataset stats yahan dikhenge.
SCANNING LIVE
0
vulnerabilities found
✅ Report link copied to clipboard!
⟺ BEFORE / AFTER — CODE DIFF
🔴 ORIGINAL (VULNERABLE)
🟢 FIXED (PATCHED)
📋 SCAN HISTORY — COMPARE & DIFF
SELECT 2 SCANS TO COMPARE — kya fix hua, kya naya aaya:
🔧 FIX PATCHER UNIT TESTS
v270 — +26 rules: NoSQL-P7 · JWT-P8 · CORS-P9 · CRLF-P10 · Deserialization-P4
—
TOTAL TESTS
—
PASSED ✅
—
FAILED ❌
—
PASS RATE
READY — v271: +12 tests (T67-T78): Go JWT·Go CRLF·BizLogic + 13 new Go security rules + 7 advanced BizLogic rules
// RUDRA Fix Patcher Tests v1.4 — v271: +T67-T78 (Go JWT·Go CRLF·BizLogic) | +13 Go rules | +7 BizLogic rules
// Tests T1-T8: SQLi·Hardcoded·FileUpload | T9-T15: XSS·Entropy | T16-T27: CMD | T28-T32: XXE | T33-T40: CSRF
// T41-T46: NoSQL | T47-T52: JWT | T53-T56: CORS | T57-T60: CRLF | T61-T66: Deser | T67-T70: Go JWT | T71-T74: Go CRLF | T75-T78: BizLogic
// Press RUN to execute...
🎯 CYBERSCAN ACCURACY BENCHMARK
TRUE POSITIVE · FALSE POSITIVE · FALSE NEGATIVE · PRECISION · RECALL
—
TOTAL TESTS
—
TRUE POS (TP)
—
FALSE POS (FP)
—
FALSE NEG (FN)
—
TRUE NEG (TN)
—
PRECISION
—
RECALL
—
F1 SCORE
READY v441 — Click RUN to start benchmark (41 test cases embedded)
// RUDRA Accuracy Benchmark v400 — Embedded self-contained benchmark (41 test cases: +15 SC v400 world-class rules)
// Tests: TP·TN·FP·FN across SQLi, XSS, CMD, PATH, SECRETS, SSRF categories
// v390: +6 new rules — XSS indirect echo, SQLi interpolation, SSRF file_get_contents, hardcoded creds, insecure cookie, open redirect superglobal
// Press RUN to execute...