Enhance static code scanning and improve pip installation method - #446
Open
ethando1984 wants to merge 36 commits into
Open
Enhance static code scanning and improve pip installation method#446ethando1984 wants to merge 36 commits into
ethando1984 wants to merge 36 commits into
Conversation
The ImportError fallback shelled out to a hardcoded `pip3`, which resolves to whatever pip is first on PATH rather than the interpreter running XSStrike. Inside a virtualenv this installed into the wrong environment, and on externally-managed installs (Homebrew, Debian) it failed outright with externally-managed-environment. Use `sys.executable -m pip` so the install always targets the running interpreter, and pass an argument list via subprocess.call so paths containing spaces aren't word-split by the shell. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
use sys.executable for fuzzywuzzy auto-install
Introduce a --scan-dir mode that statically scans a source directory for common security vulnerabilities across ~25 languages. Self-contained, pattern-based engine (no network, no extra dependencies) covering XSS, injection, insecure deserialization, path traversal, XXE, weak crypto, hardcoded secrets, SSRF, open redirect, CORS, and CSRF, each tagged with a CWE id. Supports --min-severity, --json-out, --scan-all-files, and a .xsstrikeignore file; exits non-zero on CRITICAL/HIGH findings. Also add a GitHub Actions codescan workflow (Semgrep + Gitleaks + Trivy) and document the new mode in the README. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Block commits that introduce CRITICAL/HIGH findings. The hook scans the exact staged blobs (copied from the index into a temp dir), so it checks what is being committed rather than the working tree, and it invokes the scanner module directly so it needs only the standard library. A failed scanner run exits non-zero rather than silently passing the gate. Includes an installer (core.hooksPath), a pre-commit framework config, and a .xsstrikeignore excluding XSStrike's by-design files. Also tighten the os.system rule to ignore constant string literals. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the anchor-only link scraper with extractLinks(), which also pulls href/src/action attributes and absolute or parameterised URLs embedded in inline scripts and JSON, so API endpoints on JS-heavy sites are discovered. Parameterised URLs are registered as GET forms so they become XSS-testable directly. Add an optional --headless mode (core/headlessCrawler.py) that renders pages with Playwright before scraping, recovering links injected at runtime. It degrades gracefully to plain HTTP when Playwright is absent or a render fails, and forces single-threaded crawling while active. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Expose the existing codeScan limit parameter via a --scan-limit CLI flag so users can cap how many findings are printed (0 = no limit). Findings are sorted by severity first, so the highest-impact issues are the ones shown; a note reports how many were suppressed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An unrecognized --min-severity silently fell back to the widest cutoff and reported every finding, so a typo (e.g. --min-severity HGIH) looked like a filtered run. Emit a warning naming the accepted levels (CRITICAL/HIGH/MEDIUM/LOW) when the value isn't one of them. (--scan-limit was implemented separately on the feature branch, so it is no longer included here.) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
New --prompt-injection mode tests LLM-backed endpoints by injecting instruction-override payloads into each parameter and confirming the model actually executed them. To avoid reflection false positives, a finding requires the expected output to appear in the response, be absent from a baseline request, and not be a substring of the sent payload. HIGH-confidence payloads are randomized proof-of-execution (arithmetic, string-reversal, token-concatenation); a heuristic system-prompt-leak check reports low-confidence findings. Custom payloads load from db/prompt_injection_payloads.json. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add multi-language static source code scanning
Self-contained test spins up an in-process mock LLM endpoint and asserts a vulnerable (instruction-executing) endpoint is flagged while a reflection-only endpoint is not. Wired into Travis CI; needs no network or browser and no dependencies beyond requests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add LLM prompt injection scanning mode
Two CWE-1427 rules for --scan-dir: - llm-prompt-untrusted: prompt/system/message vars built by concatenation, f-string, .format() or % interpolation. - llm-call-untrusted-input: request/user input flowing into an LLM SDK call (openai/anthropic/genai/cohere/ollama/langchain) on one line. Includes a self-contained regression test (no network/deps) that checks vulnerable prompt-building and LLM-call code is flagged while safe usage that isolates user input is not. Wired into Travis. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep runtime requirements.txt minimal; move the test-only pytest dependency into requirements-dev.txt (which pulls in the runtime deps). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ules Add static-scan rules for LLM prompt injection + split dev deps
`from modes.promptInjection import promptInjection` rebound the name that `promptInjection = args.promptInjection` had set, so the dispatch `elif promptInjection:` always evaluated the (truthy) function object. Every non-fuzz run — including --crawl — was routed into prompt-injection mode, printing "No parameters to test" instead of crawling. Check `args.promptInjection` in the condition and drop the dead, shadowed local assignment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…shadowing Fix: --prompt-injection import shadowed all other modes
Bump banner to v3.2.0 and add changelog entry covering the fork's new prompt-injection and static source scanning features. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refresh db/definitions.json from upstream RetireJS/retire.js (34 -> 76 components, current CVEs), expanding the version template placeholders to the capture-group form the plugin consumes. Harden plugins/retireJs.py against fragilities the fuller dataset exposes: - Skip JS-only regex constructs (e.g. variable-width look-behind) that Python's re can't compile, instead of aborting the whole scan - Report vulnerabilities with a missing CVE/summary as N/A rather than raising KeyError/IndexError - Deduplicate findings via json.dumps(sort_keys=True) instead of the lossy str()/quote-swap round-trip that broke on quotes in advisory text - Only report a component that actually has known vulnerabilities, so an up-to-date library matched by version alone is no longer a false positive - Remove the dead _replace_version function, whose unescaped regex emitted a SyntaxWarning on every import Docs: - README.md: document the --headless crawling and retire.js library scanning - CHANGELOG.md: add an Unreleased entry describing the above Existing test suite passes; full-DB crash sweep across all 76 components with quote/backslash-heavy payloads produces no crashes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Redesign XSStrike's terminal output with a retro DOS box-drawing aesthetic, and fix a color-detection bug that disabled all color on macOS. - colors.py: enable color on macOS/Linux TTYs (honoring NO_COLOR and piped/redirected output); add double-line box-drawing primitives (draw_box, banner, visible_len) - xsstrike.py: framed DOS-style splash banner - log.py: logger.box() renders boxed panels without a log prefix - scan.py: track target/WAF/params/reflections/payloads/vulns and print a boxed scan summary (red frame when vulnerable, green when clean) - wafDetector.py: return None instead of crashing with ValueError when the target is unreachable (status_code is None) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
--scan-dir now shows which file is currently being scanned, updated in place with a running file/finding count on interactive terminals. Piped or redirected output falls back to periodic summaries so logs stay clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
--scan-dir now draws the target as a directory tree on interactive terminals and updates each file's status in place as it is scanned (pending → scanning → clean / N findings, coloured by severity), rolling finding totals up onto the parent directories when done. Falls back to the single-line live status when the tree is taller than the terminal, and to periodic summaries when output is piped/redirected. scanDirectory now reports per-file start/finish events and accepts a pre-computed file list to avoid walking the tree twice. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Live directory tree with per-file status for --scan-dir
Adds a full-screen curses TUI for exploring a source tree and scanning on demand, in the classic NC blue theme. It reuses the --scan-dir engine (core.staticScanner) so results and .xsstrikeignore handling match the batch scan exactly. - core/ncBrowser.py: the browser (navigation, per-file/-dir live status column, results panel, file/findings pagers, function-key bar) - xsstrike.py: wire up the --browse <dir> flag - README.md / CHANGELOG.md: document the mode and its shortcuts Keys: F5/s scan selection, F2/a scan dir, F3/v view, F4/f findings, Enter open, Tab toggle panel, F1/h help, F10/q quit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Press ~ to open a command line at the bottom of the browser, type a shell command and run it in the currently browsed directory (Esc cancels). curses is suspended while it runs so output streams to the real terminal and interactive programs work; on return the listing is reloaded in case files changed. Documented in the help screen, README and CHANGELOG. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Norton Commander style interactive tree browser + scanner (--browse)
With headless now default-on, two rough edges surfaced for users who never opted in: - is_available() logged the "install Playwright" hint at error level on every crawl when Playwright was absent. Probe quietly by default and only warn (at warning level) when --headless was passed explicitly; photon() detects that and threads it through. - When Playwright imports but the browser binary is missing, _get_browser() started a driver, failed to launch, and left the driver running while _browser stayed None -- so the next URL started yet another driver, leaking one per crawled URL. Stop the driver on failure, cache the failure so is_available() short-circuits, and warn once. Both paths still fall back to plain HTTP crawling; no behaviour change when Playwright is fully installed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the three external requirements (tld, fuzzywuzzy, requests) so the core scanner runs on the stdlib alone: - tld: was unused; removed from requirements.txt - fuzzywuzzy -> difflib: new core/fuzz.py provides a partial_ratio() port of fuzzywuzzy's SequenceMatcher algorithm; core/checker.py uses it - requests -> urllib.request: core/requester.py is rewritten with a small Response shim (text/status_code/headers) and handles GET params, POST form/JSON, proxies, verify=False SSL and timeouts; HTTPError is caught so 4xx/5xx responses (needed by WAF detection) are surfaced instead of raising. core/updater.py switches to urlopen with a timeout. - xsstrike.py: drop the fuzzywuzzy auto-install bootstrap Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Interactive --browse TUI (core/ncBrowser.py): - F9/o cycles sort order (name -> severity -> size); the key was on the function bar but previously did nothing - m cycles the minimum-severity display filter (applied to glyphs, detail panel, file view and report) - e exports the visible findings to JSON (same schema as --json-out) - u toggles listing/scanning of unknown file types at runtime - status line shows the current sort/filter/all-files state - --min-severity, --json-out and --scan-all-files now seed the browser Crawling: headless Playwright rendering is now on by default; add --no-headless to force plain-HTTP crawling (falls back automatically when Playwright is absent). Docs: document the new browser keys in README and CHANGELOG, replace the dead external screenshots with ASCII layout mockups, and point all XSStrike repo/badge links at ethando1984/XSStrike. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Browser scan options, default headless rendering, and doc refresh
Make default-on headless crawling degrade quietly and leak-free
F4 (Finds) and other status-only actions appeared dead: they set self.message but _draw() never painted it, so pressing F4 on an unscanned selection produced no visible feedback. Only _flash() (used mid-scan) ever showed a message. This also silently hid feedback from sort (F9), severity filter (m), and export results (e). Draw self.message in the top status bar, taking over from the path while a message is present and keeping the sort/severity indicator. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
F5 scans the selected folder's files for XSS and F2 scans every file in the current folder; both now render a severity-coloured summary report in the footer panel (files scanned, finding counts, severity breakdown, top offending files) instead of only a transient one-line status message. The report persists until the next keypress, then per-file detail returns. Updated the module docstring, in-app help, and README to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does it implement/fix? Explain your changes.
Where has this been tested?
Python Version:
Operating System:
Does this close any currently open issues?
Does this add any new dependency?
Does this add any new command line switch/option?
Any other comments you would like to make?
Some Questions