Commit Graph
96 Commits
Author SHA1 Message Date
Lyubomir Bozhinov 32b81708ea test(ui): add semantic defect gate for inline scripts (#111 hardening) (#113)
#111 shipped 8 bad-auto-merge scars into the SPA past a CI that only ever
lints/tests `src/` — the 27k-line docs/index.html had (and still has) no
static gate. The parse test added with the #111 fix catches outright syntax
failures; this adds the *semantic* layer that parsing misses.

It runs ESLint's high-precision "possible problem" rules programmatically
over each inline <script> (no new dependency — `eslint` is already a
devDependency; no eslint.config or CI change — rides the existing `npm test`):
no-redeclare, no-unreachable, no-dupe-keys, no-dupe-args, no-dupe-else-if,
no-duplicate-case, no-const-assign, no-import-assign, no-class-assign — the
exact shapes a conflict-concatenating merge leaves behind.

Tight, always-a-bug rules, each script linted in isolation → zero false
positives on the real file. no-undef / no-unused-vars are excluded (the SPA
relies on cross-<script> and browser globals a per-block lint can't see) and
no-func-assign is excluded (the app legitimately monkey-patches navigateTo).

Verified: 0 findings on the fixed tree, and it rejects the pre-fix main
(catches the duplicate `response`). Full suite green.

Also drops a now-unused eslint-disable directive in the parse test.
2026-07-26 14:53:12 -04:00
lyubomir-bozhinov 23169db7ad test(ui): failing regression for #111 — inline script must parse
Compiles every classic inline <script> in docs/index.html with node:vm
(how a browser parses it). Fails on current main with 'Identifier
response has already been declared' — the duplicate declaration in
_safeLLMCallOnce that stops the whole SPA from booting.
2026-07-21 12:16:17 +03:00
Joseph Magly 58193d688d fix Op Admiral local-agent and approval flow (#106) 2026-07-20 14:30:45 -04:00
SiNaPsEr0x 7b1d12a07c feat: SOCKS5 egress proxy + harden local-model path (#79)
Integrate SOCKS5 attack-traffic proxying, egress leak visibility, and local-model hardening. Preserve direct local/LAN model traffic while the proxy is active and reconcile the branch with current upstream.
2026-07-20 11:54:29 -04:00
df08627cb9 feat: enhance function calling with richer schemas, validation, parallel execution, and Ollama native support (#51)
* feat: add richer JSON Schema types and AJV validation utility

- Extended ToolParameter with enum, items, properties, additionalProperties (max depth 3)
- Added ToolError class with ToolErrorCategory enum
- Added ToolValidationError interface
- Created AJV-based validateToolArgs() with lazy loading and schema depth enforcement
- 57 new tests covering types and validation

* feat: add validation gate, parallel execution, and structured error feedback

- Arsenal.execute() validates args against JSON Schema before handler execution
- Tool execution errors categorized (scope_denied, tool_not_found, timeout, execution_error, validation_error)
- ToolError import fix in agent (was missing, causing silent ReferenceError)
- Semaphore-based parallel tool execution with configurable concurrency (default 5)
- Results maintain original call order regardless of completion order
- Structured error feedback to LLM with category only (no raw error messages)
- Scope/approval gates checked per-call before execution
- 35 new tests covering validation, parallel execution, and error feedback

* feat: add Ollama native function calling with probe + cache + fallback

- Added nativeTools config option to LLMConfig
- LocalAdapter probes model support for native tools on first call
- Probe result cached per model name to avoid re-probing
- Native tools formatted as Ollama /api/chat tools parameter
- Tool calls parsed from Ollama's tool_calls response format
- Falls back to text-based renderToolContract when native not supported
- OpenAI-compatible wire format also supported (for vLLM, LM Studio)
- 10 new tests covering probe, cache, fallback, and config overrides

* fix(tools): harden validation and native fallback

---------

Co-authored-by: sronaal <sronaal@users.noreply.github.com>
Co-authored-by: Joseph Magly <1159087+jmagly@users.noreply.github.com>
2026-07-20 11:45:52 -04:00
Lyubomir BozhinovandJoseph Magly 151d3555c6 feat(ingest): multi-language white-box ingest (web-tree-sitter) (#75)
* chore(ingest): pin web-tree-sitter@0.25.10 + tree-sitter-wasms@0.1.13; add multilang-ingest design docs

* feat(ingest): multi-language grammar registry (web-tree-sitter, 8 langs, fail-open); 100% cov

* feat(ingest): language-aware param-name splitter (py/go/ts/java/c); 100% cov

* feat(ingest): tree-sitter CodeBlock extractor with wall-clock parse budget + fail-open

* feat(ingest): cross-lang sinks + multilang config + wire tree-sitter into ingestRepository (sync)

* feat(ingest): repoint white-box production callers to multilang config + prod regression test

* server-init-wiring: load multi-language grammars once at bootstrap

initGrammars() runs after LLM init, before app.listen. Internally
fail-open (never rejects): on failure the grammar registry stays empty
and ingest falls back to the Python regex parser.

* adversarial-tests: hostile-input hardening for untrusted target source

Malformed per-language source, wrong-language content, binary/non-UTF8,
empty, unicode identifiers, 20k-func large file (wall-clock budget),
deeply nested input, and a symlink-loop crawl — all must fail-open, never
throw or spin. Drives parseFileMultiLang + ingestRepository/crawl.

* readme-status + docs: flip white-box status to multi-language ingest

README source-code rows now state web-tree-sitter multi-language ingest
(fail-open to Python regex). whitebox.ts scope caveat + no-source error
message updated off the stale Python-only wording.

* coverage-setup: enforce 100% coverage gate on the three new ingest files

vitest.config.ts adds a coverage-only block (v8, perFile thresholds=100)
scoped to ts-grammars.ts, param-split.ts, ts-parse.ts. Test discovery and
env stay on defaults. Edited files gate on new-branch coverage via the
regression suites; the server.ts initGrammars bootstrap line is the
documented smoke-covered carve-out.

* review: fix WASM heap leak, language-scoped fail-open, sink recall/precision

Adversarial security + strict code review (two independent subagents)
returned one blocking bug and several correctness findings; remediated:

BLOCKING #1 — native WASM memory leak: web-tree-sitter Tree/Parser objects
were never .delete()'d. Both reviewers reproduced a process-global wedge:
after ~7 large parses the shared WASM heap exhausts, every subsequent parse
aborts (caught by fail-open), and non-Python ingest silently returns []
forever. Fix: free the tree in a finally; delete the parser in resetParser.
Regression test parses ~8MB through the real shared parser 12x.

regex, which mis-parses brace/class syntax into corrupt blocks (wrong line
spans, lost methods). Now non-.py fail-open returns [] (honest absence); the
Python regex only ever runs on .py. Isolated ts-parse-fallback test.

http(s).request, axios(config), C exec-family); negative lookbehind stops
bare system(/popen(/fetch( from matching Python receivers (os.system etc.
still matched, corpus rankings unchanged). Recall+precision tests added.

operator sees non-Python degradation.

(one-line call-graph edges, no decorators, C++ member methods).

* review round 2: fix sink-regex regressions, real timeout test, deterministic leak guard

Third review round (correctness + security re-attack + test-quality) against
the round-1 fixes surfaced issues in the fixes themselves; remediated:

- Sink-regex regressions I introduced: (1) my fetch lookbehind dropped
  window.fetch/this.fetch (top JS SSRF idiom) — reverted to \bfetch\(;
  (2) bare .Get/.Post/.Do flagged db.Get/cache.Get/queue.Do as SSRF —
  receiver-qualified to [Cc]lient. Recall+precision tests cover both;
  regex is ReDoS-free (timed).
- Placebo leak test: the 12x function-dense loop did NOT wedge the parser
  on machines with heap headroom (proven: passed with tree.delete removed).
  Replaced with a deterministic vi.spyOn(Tree.prototype,'delete') assertion,
  verified RED without the fix.
- Real (non-mocked) parse-timeout test: parseFileMultiLang gains an injectable
  budgetMs; a 0ms budget drives the real progressCallback cancellation to [].
- runWhiteboxAnalysis swap now has coverage (spy on orchestrator.run) so the
  2nd production caller can't silently revert to the Python-only config.
- Un-vacuoused weak tests: unicode now asserts the extracted block; nested/
  wrong-language wrapped in invariants() + timing bounds.
- CI now runs npm run test:coverage (the 100% gate was defined but unenforced).
- Security: documented maxFileBytes as the control bounding a single parse's
  peak WASM memory below the 2GB heap-abort ceiling.
- Stale 'fail-open to Python regex' docs fixed (ts-parse, whitebox, server,
  adversarial); circular-import note added; temp-dir cleanup; honest coverage
  wording in spec + config.

* docs(ingest): align fallback-contract text with the shipped language-scoped fail-open

Review feedback (#75, @jmagly): the design docs + one ts-grammars comment
still described the pre-implementation 'fall back to the Python regex'
model for non-Python files. The shipped contract is language-scoped: .py
uses parseFile; any non-.py file with a missing/unsupported/failed grammar
or a parse timeout returns [] (never the Python regex, which would mis-parse
brace/class syntax into corrupt blocks). Updated every stale reference in
multilang-ingest-spec.md, multilang-ingest-plan.md, and ts-grammars.ts so
the docs match the security boundary. Docs/comment only — no code change.

* fix(test): make the ReDoS wall-clock guard robust under coverage instrumentation

Review feedback (#75, @jmagly): the CI step this PR adds (npm run
test:coverage = vitest run --coverage) runs the full suite under V8
coverage, and that overhead pushes the pathological-brace DoS timing guard
in local-agent-tool-calling.test.ts:69 over its <300ms bound (320 < 300
fails on CI). Raise the bound to 1000ms — still 2x below the ~2100ms
quadratic-ReDoS regression it guards against, so it fails hard if the
regression returns, but no longer false-fails under coverage/slow CI.

Chose the reviewer's option (a) (robust bound) over scoping test:coverage,
so the gate stays a simple full-suite run and no test-file enumeration can
rot. Verified: npm run test:coverage is green and the 3 new files stay at
100%.

* fix(ingest): cover pointer-returning C functions

---------

Co-authored-by: Joseph Magly <1159087+jmagly@users.noreply.github.com>
2026-07-20 11:41:21 -04:00
Krzysztof MarciniakandJoseph Magly 440dedd9c1 feat: update DeepSeek models to V4 Flash and V4 Pro (#103)
* feat: update DeepSeek models to V4 Flash and V4 Pro

- Replace deprecated deepseek-chat / deepseek-reasoner with deepseek-v4-flash / deepseek-v4-pro
- Update base URL from api.deepseek.com/v1 to api.deepseek.com
- Update context window (1M) and max output (384K) per official API docs
- Old models deprecated 2026-07-24

* fix: resolveGeneralLLMConfig missing baseUrl + Admiral timeout 180s

resolveGeneralLLMConfig constructed a new LLMConfig but omitted
baseUrl, causing the adapter to fall back to api.openai.com/v1
regardless of provider — DeepSeek keys hit OpenAI (401).
Also raised Admiral preview timeout to 180s for thinking-mode models.

* fix: createTempestCommandInstance missing baseUrl for operator exec

Operator LLM calls also lacked baseUrl, same 401-for-DeepSeek bug
as resolveGeneralLLMConfig. Reads provider-specific baseUrl from config.

* fix(deepseek): migrate retired persisted defaults

---------

Co-authored-by: Joseph Magly <1159087+jmagly@users.noreply.github.com>
2026-07-20 11:36:50 -04:00
Lyubomir BozhinovandJoseph Magly 9cce68e804 feat(settings): Universal API Config panel with server-side model fetch (#90) (#101)
* feat(settings): Universal API Config panel with server-side model fetch (#90)

Consolidates provider configuration into one "Universal API Config" panel in
Settings — provider dropdown (OpenAI-compatible / Anthropic), base URL, API key,
model with a live "Fetch models" button, and max context tokens — above the
existing per-provider key sections.

Backward-compatible by design: the panel reads and writes the SAME state.settings
keys the individual sections already use (${provider}Key, selectedModel), so
nothing migrates and nothing is lost; the individual sections keep working and
stay in sync.

- src/config/provider-models.ts (new): listProviderModels queries a provider's
  own model endpoint (OpenAI-compatible Bearer /models, Anthropic x-api-key
  /v1/models, OpenRouter public list); resolveModels wraps it fail-open.
- POST /api/models (new route): server-side so the browser dodges provider CORS.
  Binds key+baseUrl by source — a caller-supplied base URL must bring its own
  key, so the server never lends its configured key to a body-chosen URL. Always
  responds, failing open to the static AVAILABLE_MODELS list on a missing key,
  network error, or unknown provider (incl. local-agent) — never hangs.
- Model options are built via the DOM API (createElement/textContent), never
  innerHTML, so untrusted provider-returned model ids cannot inject markup.

Scope notes: augment-not-replace (removing the individual sections is deferred
to maintainer preference); base URL + context cap are stored and used for model
discovery and server/agent flows — in-browser mission routing still uses
OpenRouter/Venice, matching the existing "not wired" hints; the "Model Reasoning
(Eino)" sub-proposal is a separate follow-up pending a mapping.

Verified on macOS: 12 unit tests (RED->GREEN) for the model module, full suite
462 green, and Playwright QA (17 checks) driving the real panel — render,
provider switch, persistence across reload, backward-compat, and both the static
and live Fetch paths.

Refs #90

* fix(settings): harden model list fetch

---------

Co-authored-by: Joseph Magly <1159087+jmagly@users.noreply.github.com>
2026-07-20 11:34:26 -04:00
Joseph Magly be3eb7cb44 Merge remote-tracking branch 'upstream/main' into pr-70
# Conflicts:
#	src/config/index.ts
#	src/llm/index.ts
#	src/server.ts
#	src/setup.ts
#	src/types/index.ts
2026-07-17 01:39:59 -04:00
Joseph Magly cc9516a980 Merge pull request #44 from mahdi-salmanzade/feat/arsenal-recon-adapters
feat(arsenal): add six keyless recon/OSINT tool adapters
2026-07-17 01:31:14 -04:00
Joseph Magly 5a12593baa Merge remote-tracking branch 'upstream/main' into pr-45
# Conflicts:
#	src/config/index.ts
#	src/types/index.ts
2026-07-16 12:11:16 -04:00
Joseph Magly 95868c3d37 Merge remote-tracking branch 'upstream/main' into pr-47
# Conflicts:
#	README.md
2026-07-16 11:55:20 -04:00
Joseph Magly db48d881f7 Merge branch 'pr-80' into pr80-delivery
# Conflicts:
#	docs/index.html
#	src/__tests__/local-api-hardening-static.test.ts
2026-07-16 01:18:03 -04:00
Joseph Magly 29c477d246 Merge branch 'pr-18' into pr-delivery-74-94-18-39-41
# Conflicts:
#	.gitignore
#	src/agent/local-agents.ts
2026-07-16 00:52:31 -04:00
Joseph Magly 5921221c9b Merge branch 'pr-41' into pr-delivery-74-94-18-39-41 2026-07-16 00:49:26 -04:00
Joseph Magly b76853893a Merge branch 'pr-39' into pr-delivery-74-94-18-39-41 2026-07-16 00:49:26 -04:00
Joseph Magly 9775038507 Merge branch 'pr-94' into pr-delivery-74-94-18-39-41 2026-07-16 00:49:26 -04:00
Joseph Magly 8e82e1c2ba Merge branch 'pr-74' into pr-delivery-74-94-18-39-41 2026-07-16 00:49:26 -04:00
Fred BlaiseandFred Blaise 26fe8495b9 feat: allow origin-scoped target headers from env (#65)
Enable authenticated scans across the HTTP arsenal while binding configured credentials to an exact target origin.

Includes case-insensitive per-request overrides, cross-origin redirect containment, protected curl configuration, result redaction, documentation, and regression coverage.

Co-authored-by: Fred Blaise <fred.blaise@protonmail.com>
2026-07-15 23:07:08 -04:00
Joseph MaglyandPazificateur69 cf0090adf4 feat(arsenal): add source and supply-chain parsers (#97)
Follow-up to the JSON-scanner parser layer: wire semgrep, gitleaks, trivy and
grype into parseToolOutput so their findings become structured, gate-verifiable
evidence instead of raw text (they were parserStatus:'planned').

- semgrep  (scan --json)          → one finding per rule match; ERROR/WARNING/INFO
                                     mapped to severity; CWE token pulled from
                                     metadata (e.g. "CWE-78: …" → CWE-78); refs → remediation.
- trivy    (fs --format json)     → one finding per package vuln; CVE + CweIDs +
                                     "upgrade <pkg> to <fixed>" remediation.
- grype    (dir:. -o json)        → one finding per match; CVE + package coordinates.
- gitleaks (detect --report json --redact) → one high finding per secret. Defence in
                                     depth: the details are run through redactString()
                                     so a raw secret can NEVER reach a finding / the vault,
                                     even though the adapter already passes --redact.

Broadens the severity map to cover scanner vocabularies (ERROR/WARNING, CRITICAL…
NEGLIGIBLE, moderate) onto the five canonical levels. Flips parserStatus to
'structured' for the four tools. Extends parsers.test.ts + fixtures: field mapping,
the gitleaks redaction guarantee, and the end-to-end gate pass for every new scanner.

Stacked on the parser layer (#42); pairs with the scanner-invocation fix (#40) that
gives these tools the JSON-emitting arg templates. Until #40 lands the parsers simply
degrade to [] (no JSON to parse) — no misbehaviour. Secret scanners beyond gitleaks
and SARIF-style tools remain a follow-up.

Co-authored-by: Pazificateur69 <agagliardi@guardiaschool.fr>
2026-07-15 19:45:58 -04:00
Pazificateur69 f8c283377c feat(arsenal): parse scanner JSON into structured findings (#42)
The generic adapter factory returned raw stdout only (`adapter-tools.ts` success
path), so 35 catalogued scanners with `parserStatus: 'planned'` never populated the
structured `ToolResult.findings` channel — their output was dropped on the floor and
the agent could neither verify nor chain on it. The whole downstream pipe already
exists and is honest-by-construction: the agent loop stamps `provenance:'tool'` + the
raw output, the operator materialises each finding with output-evidence, and the live
gate (`evidence/gate.ts`) marks it verified.

Add `src/arsenal/parsers.ts` — `parseToolOutput(toolId, rawStdout) → ToolFinding[]`
for the five scanners that already emit machine-readable JSON via their existing arg
templates (zero template changes): nuclei (-jsonl), httpx (-json), dalfox (--format
json), ffuf (-of json), katana (-jsonl). Parsers are pure, dependency-free, and NEVER
throw: empty/garbled/unknown input yields `[]`, never a fabricated finding (same
discipline as stub-honesty / no-phantom-tools). The factory attaches parsed findings
while ALWAYS keeping the raw stdout as `output` — the evidence of record the gate checks.

- nuclei/dalfox emit CWE, which the tool channel dropped: add optional `cwe?: string[]`
  to `ToolFinding` and thread it through the operator's finding materialisation.
- flip `parserStatus: 'planned' → 'structured'` for httpx, dalfox, katana (nuclei/ffuf
  were already structured).

Adds `src/__tests__/parsers.test.ts` + fixtures: per-scanner field mapping, the
honesty contract (empty/garbled/adversarial → [], no throw), a factory-wiring check
that a minted adapter returns findings while preserving raw stdout, and an end-to-end
assertion that every parsed finding PASSES `gateLiveFinding` with provenance='tool'.

The minted-adapter path is gated behind T3MP3ST_FULL_ARSENAL, so the benchmarked
default arsenal is untouched. Supply-chain JSON tools (semgrep/gitleaks/trivy/grype)
and secret scanners (need redaction) are a clean follow-up.
2026-07-15 19:43:51 -04:00
adrianwandCodex 089591b18f feat(scan): add live progress and recon bootstrap (#81)
* Add live scan progress view

* Make local-agent recon report real tool progress

* Feed recon bootstrap into local agent ReAct loop

* Remove stale local-agent JSON tool parser

* Label backend-seeded scan progress

---------

Co-authored-by: Codex <codex@openai.com>
2026-07-15 19:42:20 -04:00
Lyubomir Bozhinov 5b4ac700ad fix(agents): detect local CLIs via well-known install dirs (#83)
A T3MP3ST server launched from Finder, the desktop app, or any non-interactive
shell inherits launchd's minimal PATH (/usr/bin:/bin:/usr/sbin:/sbin). The
local-agent detector resolved `claude`/`codex`/`hermes` against that PATH via
execFile, so an installed, authed CLI in ~/.local/bin (Claude Code's native
installer), Homebrew, npm-global, or a version-manager shim (mise/nvm/fnm) threw
ENOENT and was reported installed:false — the Settings "Connect Local Agents"
checkboxes went dead and it read like a UI bug.

Add resolveBin(): pure-fs (no shell) resolution over PATH plus a curated set of
well-known install dirs under the real agent home (agentHome(), so a HOME
redirect can't hide them), with an executable-file access check and fail-open to
the bare name — an unresolved name yields the same ENOENT → installed:false as
before, so true-absence detection is unchanged. Route the detector and both spawn
sites (runLocalAgent, localAgentChat) through it, so a CLI detected under a
minimal PATH also actually spawns. Bound the keychain auth-probe with a 2s
timeout so a locked/headless keychain (the same non-interactive launch context)
can't hang detection.

POSIX/macOS-scoped: resolveBin short-circuits on win32 — Windows resolution
(where.exe / .cmd shims) is handled by the complementary open PR #18.

Verified on macOS: RED->GREEN unit + integration tests (resolver, detector
wiring, and both spawn sites), and manual QA driving the real Web UI under a
reproduced minimal PATH (Claude Code flips from "Not installed" to detected).

Refs #78 — fixes the macOS/POSIX variant. The original report was a Windows
Sandbox environment (PR #18's domain), so this intentionally does not auto-close
that issue.
2026-07-15 19:39:59 -04:00
Joseph Magly db2d270af5 fix(server): avoid caller cwd dotenv loading (#96) 2026-07-15 19:39:12 -04:00
Joseph Magly 51f610f3a5 fix(local-agents): support current Codex exec CLI (#95) 2026-07-15 19:09:34 -04:00
Joseph Magly 4b81bf6436 fix(local): honor server LLM for keyless missions 2026-07-15 18:13:27 -04:00
Joseph Magly 600f43b8b1 fix(local): merge system prompts for vLLM 2026-07-15 18:13:00 -04:00
Eddy 25f86b0c66 fix: reject curl destination override flags
* fix: reject curl destination override flags

* fix: block additional curl target bypass forms
2026-07-15 18:12:35 -04:00
Joseph Magly 84fcef5428 fix: clarify local LLM setup 2026-07-15 18:12:12 -04:00
psighoandClaude Opus 4.8 7127fe8220 fix(server): accept same-origin requests from a non-loopback UI bind (#84)
When the operator binds the server to a non-loopback address
(T3MP3ST_HOST=0.0.0.0 or a LAN IP) they've explicitly opted into network
access — the same decision that already stands the anti-rebinding Host guard
down. But the CSRF origin guard and the SSE guard were NOT updated to match:
they still only trust loopback origins, so the operator's own LAN-served UI
(e.g. http://192.168.x.x:3333/ui) had every state-changing request and the
event stream rejected with "Cross-origin request rejected". That makes hunts
fail on any target from a LAN-accessed War Room (issue #84).

Fix: add isSameOriginAsHost() and, ONLY on a non-loopback bind, also trust a
request whose Origin/Referer host:port equals this server's own Host header —
i.e. a genuine same-origin request from the operator's own UI. A foreign origin
(evil.com) still mismatches the Host and is rejected, so the CSRF/drive-by
protection is preserved. On a loopback bind the branch is skipped entirely:
the strict loopback-only gate plus the Host guard remain fully in force, so
there is no new CSRF or DNS-rebinding surface for the default configuration.

Verified against a 0.0.0.0-bound instance:
  - same-origin LAN request  (Origin==Host, non-loopback) → passes the guard ✅
  - foreign origin (evil.com)                             → still 403 ✅
  - no Origin (curl/CLI)                                  → allowed ✅
Typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 01:57:09 +05:00
Codex 6fef62aa8e Narrow authorize-target to pending approvals 2026-07-12 09:50:43 -04:00
Codex 3d6dc62957 Tighten approval receipt scoping 2026-07-12 09:50:43 -04:00
Codex 964fe5b3ba Add scope receipts approval UI 2026-07-12 09:50:43 -04:00
Codex d500a29186 Ask approval for Admiral expanded scope 2026-07-12 09:50:43 -04:00
Codex f2ec1e9437 Reuse target-scoped approval receipts 2026-07-12 09:50:42 -04:00
Mahdi Salmanzadeh Asl de7ee804e6 feat(arsenal): add six keyless recon/OSINT adapters with arg templates
Adds whatweb, wafw00f, amass, dnsx, testssl.sh, and waybackurls to the
arsenal catalog — all keyless, non-dangerous recon/OSINT tools that fill
live gaps in web fingerprinting, WAF detection, passive attack-surface
mapping, DNS validation, TLS posture, and historical-URL discovery.

Each adapter follows the CONTRIBUTING.md checklist and each gets an explicit
ARG_TEMPLATES entry in adapter-tools.ts, so:

  - amass uses the required `enum -passive -d <target>` form (not a bare
    positional), and dnsx passes the target via `-d` with resolve flags —
    both fixing the broken default-positional invocation flagged in review.
  - all six are accounted-for (templated), so they never land in the
    arsenal-count-honesty guard's UNACCOUNTED set — no KNOWN_DEBT needed.

Scoped to the six adapters and their templates only. typecheck clean,
tests pass.
2026-07-11 19:11:13 +04:00
エルジー🐧 64efcf6373 Update index.ts 2026-07-11 06:04:11 +07:00
エルジー🐧 788e90e0ee Update index.ts 2026-07-11 05:48:06 +07:00
エルジー🐧 971a452eac Update index.ts 2026-07-10 22:56:13 +07:00
エルジー🐧 13fe0f2e56 Update index.ts 2026-07-10 22:30:20 +07:00
psighoandClaude Opus 4.8 bf50be9971 harden(local-agents): close cmd.exe prompt-injection + POSIX detect fallback
Addresses review feedback on the Windows detection PR.

1. Command injection (the important one). spawnAgent ran .cmd/.bat shims via a
   hand-rolled `spawn('cmd.exe', ['/d','/s','/c', shim, ...args])`. cmd.exe
   re-parses its tail with its own rules and ignores `\"`-escaping, so an
   adversarial prompt (claude `-p <prompt>`, codex `exec <prompt>`) containing
   `"` + `& | > %VAR%` broke out and executed — the BatBadBut / CVE-2024-1874
   class. Verified with a `x" & echo PWNED` payload: it ran.
   Fix: use Node's own safe `.cmd` handling — `spawn(shim, args, {shell:true})`.
   On Node >=18.20.2 / >=20.12.2 / >=21 (CVE-2024-27980) Node escapes each arg
   for cmd, so the whole prompt lands as ONE literal argument and cannot break
   out (verified on Node 24: the same payload arrived intact in %1). .exe/POSIX
   still spawn directly with shell:false.

2. POSIX detection regression. Detection gated on resolveBin() returning a
   value; on a bash-less/busybox image where both `command -v` and `which` are
   absent, an installed agent flipped to "not installed". Fix: on POSIX fall
   back to the bare name (`resolveBin(bin) || (isWindows ? undefined : bin)`) —
   the OS resolves PATH at exec time and the ENOENT branch still catches
   genuinely-absent binaries. Windows keeps resolveBin authoritative.

Typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 05:03:42 +05:00
psighoandClaude Opus 4.8 a836e61adb fix(local-agents): don't 500 /detect when a version-probe spawn is denied
detectOne() ran the `--version` probe via execFile INSIDE a `new Promise`
executor but only handled the async error path. execFile can throw
SYNCHRONOUSLY (e.g. `spawn EPERM` when child-process creation is restricted),
and a synchronous throw in a Promise executor REJECTS the promise. Because
detectLocalAgents() used Promise.all, one agent's spawn failure rejected the
whole batch → GET /api/agents/local/detect returned 500 → the Settings "Local
Agents" card silently rendered "0/0 installed" even though all CLIs were on PATH.

- detectOne: wrap execFile in try/catch. The binary was already found on PATH
  (resolveBin returned a path) so it IS installed; on a sync throw we resolve
  installed:true with version '?' and filesystem-based auth, never rejecting.
- detectLocalAgents: Promise.allSettled instead of Promise.all, so one agent's
  failure degrades to "not installed" for that agent only, never the batch.

Verified: /detect returns 200 with claude/codex/hermes installed+ready.
Typecheck clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 03:22:46 +05:00
psigho 6ba02ec50d fix(local-agents): Windows CLI detection + Hermes auth path
Detection reported installed npm-global agents (Claude Code, Codex) as
'binary not found on PATH' on Windows, and an authed Hermes desktop as
'NOT AUTHED'. Two root causes:

1. resolvePath() used POSIX-only 'command -v'/'which', and
   execFile/spawn('claude', ...) cannot resolve npm's .cmd shims via
   PATHEXT -> ENOENT -> installed:false. Add resolveBin() (where.exe on
   Windows, preferring .exe > .cmd > .bat) and route detection + both
   spawn call sites through the resolved path.

2. Hermes desktop on Windows stores its login under %LOCALAPPDATA%\hermes   not ~/.hermes/. Add localAppData() and check both (presence-only).

Windows .cmd shims are launched via a new spawnAgent() helper that invokes
cmd.exe with an argv ARRAY (shell:false) instead of shell:true, so the
untrusted prompt is never re-parsed by cmd.exe -> no command-injection surface.

No new deps; typecheck clean.
2026-07-10 03:22:46 +05:00
Joseph Magly df37e7c423 Address upstream issues 60 and 62 2026-07-09 11:50:16 -04:00
Joseph Magly 0b2c4f545a fix: clarify local LLM setup 2026-07-09 10:48:06 -04:00
pliny ae32cf5051 Merge pull request #54 from Pazificateur69/feat/arsenal-re-analysis-invocations
feat(arsenal): real invocations for the reverse-engineering / mobile / smart-contract analysis loadout
2026-07-09 08:51:34 -04:00
Joseph Magly 5e40e60f47 feat(llm): native Google Gemini provider via OpenAI-compatible endpoint
Add a first-class `gemini` provider so operators can drive missions with a
direct GEMINI_API_KEY, instead of only reaching Gemini through OpenRouter.

Gemini is wired exactly like xAI: dispatched through OpenAIAdapter against
Google's OpenAI-compatible surface. The base URL is
https://generativelanguage.googleapis.com/v1beta/openai — the `/openai`
segment is required because OpenAIAdapter posts to `${baseUrl}/chat/completions`;
without it requests hit `/v1beta/chat/completions`, which Google does not serve.

Wires the provider through the type union, adapter factory, config
(interface, defaults, model catalog, key env map, getLLMConfig, fallback
chain, redaction, .env template), and adds regression tests pinning the
`/openai` base-URL segment.
2026-07-08 11:59:18 -04:00
Pazificateur69 353ea33a23 feat(arsenal): real invocations for the reverse-engineering / mobile / smart-contract analysis loadout
The Kali+ adapter factory only carries bespoke ARG_TEMPLATES for the network
and source/supply-chain scanners. The reverse-engineering, mobile and
smart-contract analysers catalogued by the cloud/mobile/binary-RE loadouts fall
through to DEFAULT_TEMPLATE and spawn a bare `<binary> <file>` — a broken
invocation for a subcommand/flag-driven tool, and for radare2 one that drops
into an INTERACTIVE prompt and hangs the agent loop until the timeout burns out.

Add conservative, read-only ARG_TEMPLATES (mirroring each catalog commandHint)
for objdump, readelf, checksec, r2, exiftool, myth (mythril), apkleaks, slither
and mobsfscan. File-oriented tools resolve their artifact through a new
`artifactPath` helper that refuses an absent path or an inherited http(s) URL by
throwing, which the handler turns into a clean {success:false} result (never a
bare `objdump ''`). No intrusive or code-executing flag is added — risk stays
where the catalog put it, and the existing option-looking-target / scope gates
still apply.

Add an invocation-honesty guard test (sibling of the tool-count honesty test):
every mintable adapter must be either templated or explicitly filed under one
fall-through reason — POSITIONAL_TARGET_OK, OPERATOR_DRIVEN, or KNOWN_DEBT — so a
newly catalogued subcommand tool can never silently ship a broken positional
invocation, and the remaining debt (feroxbuster, osv-scanner, hashcat, apktool,
yara) is tracked in the open rather than hidden.

All offline gate checks pass (lint typecheck test doctor verify-claims
test:no-fitting test:no-self-fitting test:gate prompt:audit smoke
test:arsenal-tools arsenal:smoke).
2026-07-08 10:28:23 +02:00
Codex 23713fa177 Document local agent timeout tuning 2026-07-07 16:05:20 -04:00
Codex 75b7ca02ef Honor local agent timeout defaults 2026-07-07 16:05:20 -04:00