Skip to content

Enhance static code scanning and improve pip installation method - #446

Open
ethando1984 wants to merge 36 commits into
s0md3v:masterfrom
ethando1984:master
Open

Enhance static code scanning and improve pip installation method#446
ethando1984 wants to merge 36 commits into
s0md3v:masterfrom
ethando1984:master

Conversation

@ethando1984

Copy link
Copy Markdown

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

  • I have documented my code.
  • I have tested my build before submitting the pull request.

ethando1984 and others added 20 commits August 6, 2026 20:54
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>
ethando1984 and others added 2 commits August 7, 2026 08:03
--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>
ethando1984 and others added 6 commits August 7, 2026 08:29
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>
ethando1984 and others added 8 commits August 7, 2026 10:45
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant