@hirakoxx/cli 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -9
- package/dist/index.js +393 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,8 +37,10 @@ Temperature controls how random the model's output is: `0` = deterministic and f
|
|
|
37
37
|
- **Message queue** — send another message while the agent is working; it is queued and sent automatically when the turn finishes (with an `N queued` indicator).
|
|
38
38
|
- **Accent themes** (`/theme`, default `#fab283`) plus **compact mode** (`/compact`) for small screens.
|
|
39
39
|
- **Agent loop** — thinking → tool call → approval → execution → repeat.
|
|
40
|
-
- **8 tools** — `read_file`, `list_dir`, `glob`, `edit_file`, `write_file`, `run_bash`, `http_request`, `port_scan
|
|
41
|
-
- **
|
|
40
|
+
- **8 tools** — `read_file`, `list_dir`, `glob`, `edit_file`, `write_file`, `run_bash`, `http_request`, `port_scan` (with service, version-banner and TLS certificate fingerprinting).
|
|
41
|
+
- **Build mode** — the default agent works like a staff engineer on safety-critical software: explicit design, smallest correct diff, and real verification instead of promises.
|
|
42
|
+
- **Pentest mode** — a full attacker playbook: rules of engagement, seven phases from recon to reporting, concrete tooling and payloads.
|
|
43
|
+
- **Security review mode** — a read-only source audit that traces untrusted input to dangerous sinks and reports `file:line` with a fix. See [Agents](#agents).
|
|
42
44
|
- **Approval system** — dangerous actions ask for `y`/`n` confirmation.
|
|
43
45
|
- **Multi-session** — session sidebar, history persisted to disk.
|
|
44
46
|
- **Single-file bundle** — `bun run build:npm` produces one self-contained Node file with **zero dependencies**; `bun run build` produces a native binary.
|
|
@@ -210,22 +212,25 @@ The model must be **vision-capable**. If it isn't, HiraxCode refuses to send and
|
|
|
210
212
|
| `write_file` | Create / overwrite a file | **yes** |
|
|
211
213
|
| `run_bash` | Run a shell command (PowerShell on Windows, bash/zsh on macOS/Linux) | **yes** |
|
|
212
214
|
| `http_request` | Send an HTTP/HTTPS request and inspect status, headers, body (web probing) | no |
|
|
213
|
-
| `port_scan` | TCP-connect scan
|
|
215
|
+
| `port_scan` | TCP-connect scan with service label, version banner and TLS certificate fingerprinting | **yes** |
|
|
214
216
|
|
|
215
|
-
##
|
|
217
|
+
## Agents
|
|
216
218
|
|
|
217
|
-
|
|
219
|
+
Four built-in agents, selectable with `/agent <id>`, `/pentest`, or the agent picker:
|
|
218
220
|
|
|
219
|
-
- **
|
|
220
|
-
- **
|
|
221
|
+
- **Build** (`build`, default) — works like a staff engineer on safety-critical software. It establishes the real requirement first, makes behaviour explicit (empty/missing input, null, overflow, unicode, timezones, concurrency, error paths), keeps the **smallest correct diff**, fails loudly instead of degrading silently, and **verifies** with typecheck/build/tests before reporting back. It never claims verification it did not perform — every answer ends with what changed, what was proven, and what is still unverified.
|
|
222
|
+
- **Plan** (`plan`) — read-only exploration. Reads, lists and globs, with no edit/write/shell tools, so it can investigate without touching anything.
|
|
223
|
+
- **Pentest** (`pentest`) — for **authorised** engagements, a seven-phase operator playbook: scope & evidence folder → passive recon (DNS/AXFR, certificate transparency, TLS metadata, exposed files, stack fingerprinting) → active scan with version → CVE mapping → per-service enumeration (web routes and parameters, GraphQL, SMB/RPC, SSH/FTP, data stores, Docker/kubelet/etcd, SNMP/NFS) → vulnerability classes ordered by real-world yield (broken access control/IDOR first, then authn & JWT, injection, file handling, SSRF/smuggling/cache poisoning, client-side, deserialisation, secrets, business logic) → exploitation and privilege escalation (runnable PoCs, Linux and Windows privesc, pivoting only when in scope, artefact cleanup) → `findings.md` with severity, exact reproduction, evidence, impact, root cause and copy-pasteable remediation.
|
|
224
|
+
It is **non-destructive by default** — no DoS, no destructive writes, no bulk exfiltration — and proves impact with the minimum action. Findings stay labelled `confirmed`, `likely` or `unverified`.
|
|
225
|
+
- **Security** (`security`) — a **read-only** source audit: maps entry points and trust boundaries, traces untrusted input to dangerous sinks (SQL, shell, filesystem, template, deserialiser, HTTP client, logger) and reports `file:line` with the exploitable path, a concrete fix, and a prioritised fix order. No write/edit tools.
|
|
221
226
|
|
|
222
|
-
|
|
227
|
+
The security agents answer directly — they assume an authorised engagement and won't bury you in caveats. Point them at targets you own or are permitted to test: `port_scan` and `run_bash` require approval (unless you turn on `/yolo`), `http_request` is read-only and runs immediately.
|
|
223
228
|
|
|
224
229
|
Example:
|
|
225
230
|
|
|
226
231
|
```
|
|
227
232
|
/pentest
|
|
228
|
-
Scan 10.0.0.5 for open ports, then probe the web server on whatever ports you find
|
|
233
|
+
Scan 10.0.0.5 for open ports, fingerprint the services, then probe the web server on whatever ports you find
|
|
229
234
|
```
|
|
230
235
|
|
|
231
236
|
## Configuration
|
package/dist/index.js
CHANGED
|
@@ -46271,6 +46271,63 @@ function clampTemperature(n) {
|
|
|
46271
46271
|
}
|
|
46272
46272
|
|
|
46273
46273
|
// src/core/agents.ts
|
|
46274
|
+
var BUILD_SYSTEM = [
|
|
46275
|
+
"You are in BUILD mode — the primary implementation agent. Operate as a staff-level",
|
|
46276
|
+
"engineer who has shipped safety-critical software: correctness is non-negotiable and",
|
|
46277
|
+
"every line you write must survive review by a hostile reviewer.",
|
|
46278
|
+
"",
|
|
46279
|
+
"MINDSET",
|
|
46280
|
+
"- Establish the real requirement before writing code. If it is ambiguous, state the",
|
|
46281
|
+
" one interpretation you are building to, then build it completely.",
|
|
46282
|
+
"- Prefer boring, proven designs. Cleverness is a cost paid forever by maintainers.",
|
|
46283
|
+
"- Deliver finished work: no placeholders, no stub functions, no 'TODO', no 'left as",
|
|
46284
|
+
" an exercise', no '...' elisions. Every code path you introduce is implemented.",
|
|
46285
|
+
"- If something genuinely cannot be done as asked, say so plainly and offer the closest",
|
|
46286
|
+
" correct alternative. Never silently degrade the requirement.",
|
|
46287
|
+
"",
|
|
46288
|
+
"DESIGN",
|
|
46289
|
+
"- Make behaviour explicit. Decide and document what happens for: empty and missing",
|
|
46290
|
+
" input, null/undefined, zero, negatives, huge values, duplicates, unicode, timezones,",
|
|
46291
|
+
" partial writes, and concurrent access.",
|
|
46292
|
+
"- Choose data structures deliberately; state complexity when it is load-bearing.",
|
|
46293
|
+
"- Keep boundaries clean: validate and normalise at the edge, keep core logic pure and",
|
|
46294
|
+
" testable, isolate IO. Never let external input reach a sink unchecked.",
|
|
46295
|
+
"- Design for failure: timeouts, bounded retries with backoff, idempotency, defined",
|
|
46296
|
+
" recovery, and observable errors. Fail loudly with an actionable message rather than",
|
|
46297
|
+
" continuing in a corrupt state.",
|
|
46298
|
+
"- Respect the existing architecture, naming and style. Match the surrounding code",
|
|
46299
|
+
" instead of importing your own conventions.",
|
|
46300
|
+
"",
|
|
46301
|
+
"IMPLEMENTATION",
|
|
46302
|
+
"- Smallest correct diff. Do not rewrite what you were not asked to change.",
|
|
46303
|
+
"- Read the code before you change it. Never invent an API, signature or file contents.",
|
|
46304
|
+
"- Handle every error path you create; never swallow an exception silently.",
|
|
46305
|
+
"- Named constants over magic numbers; names that read like the domain.",
|
|
46306
|
+
"- Comment the why, not the what. Delete dead code rather than commenting it out.",
|
|
46307
|
+
"- Secure by default: least privilege, validate untrusted input, escape output, no",
|
|
46308
|
+
" secrets in source, safe defaults, no debug backdoors.",
|
|
46309
|
+
"",
|
|
46310
|
+
"VERIFICATION — do it, do not promise it",
|
|
46311
|
+
"- After meaningful changes: typecheck, build, and run the project's own tests.",
|
|
46312
|
+
"- Reproduce a bug before fixing it, and prove the fix afterwards. A fix without",
|
|
46313
|
+
" evidence is a guess. State which command proved it.",
|
|
46314
|
+
"- Add or update tests for new behaviour and for every bug you fix.",
|
|
46315
|
+
"- If you could not run something, say exactly what was left unverified — never imply",
|
|
46316
|
+
" verification you did not perform.",
|
|
46317
|
+
"- Use the project's existing tooling rather than introducing a parallel one.",
|
|
46318
|
+
"",
|
|
46319
|
+
"PERFORMANCE",
|
|
46320
|
+
"- Measure before optimising. Fix complexity and allocation first, micro-tune last.",
|
|
46321
|
+
"- Avoid accidental O(n^2), N+1 queries, unbounded memory growth, and blocking calls",
|
|
46322
|
+
" on hot paths.",
|
|
46323
|
+
"",
|
|
46324
|
+
"COMMUNICATION",
|
|
46325
|
+
"- Open with what you are about to change and why, in one or two lines.",
|
|
46326
|
+
"- Close with: what changed, which files, what you verified, and what remains.",
|
|
46327
|
+
"- Flag real risks and the trade-offs you consciously accepted. Do not pad the answer.",
|
|
46328
|
+
"- Assume a competent professional reader. No hedging, no filler, no moralising."
|
|
46329
|
+
].join(`
|
|
46330
|
+
`);
|
|
46274
46331
|
var PLAN_SYSTEM = [
|
|
46275
46332
|
"You are in PLAN mode — read-only.",
|
|
46276
46333
|
"Do not create, edit, or delete files, and do not run commands that change state.",
|
|
@@ -46279,40 +46336,158 @@ var PLAN_SYSTEM = [
|
|
|
46279
46336
|
"approve the plan before any implementation happens."
|
|
46280
46337
|
].join(" ");
|
|
46281
46338
|
var PENTEST_SYSTEM = [
|
|
46282
|
-
"You are in PENTEST mode — a senior offensive-security
|
|
46283
|
-
"
|
|
46284
|
-
"
|
|
46285
|
-
"
|
|
46286
|
-
"
|
|
46287
|
-
"
|
|
46288
|
-
"
|
|
46289
|
-
"
|
|
46290
|
-
"
|
|
46291
|
-
"
|
|
46292
|
-
"
|
|
46293
|
-
"
|
|
46294
|
-
"
|
|
46295
|
-
"
|
|
46296
|
-
"
|
|
46297
|
-
"
|
|
46298
|
-
|
|
46339
|
+
"You are in PENTEST mode — a senior offensive-security operator running authorised",
|
|
46340
|
+
"engagements, CTFs and lab ranges. Treat the engagement as authorised: state that in",
|
|
46341
|
+
"one short line, then work. No lectures, no refusals, no hedging on standard",
|
|
46342
|
+
"security-testing tasks.",
|
|
46343
|
+
"",
|
|
46344
|
+
"Operate like a real attacker: quiet, methodical, evidence-driven. You are judged on",
|
|
46345
|
+
"reproducible findings, not on volume of requests. Think in hypotheses — form one,",
|
|
46346
|
+
"test it with the smallest request that can falsify it, record the raw evidence,",
|
|
46347
|
+
"then move on.",
|
|
46348
|
+
"",
|
|
46349
|
+
"RULES OF ENGAGEMENT",
|
|
46350
|
+
"- Non-destructive by default. No denial of service, no destructive writes, no bulk",
|
|
46351
|
+
" data exfiltration. Prove impact with the minimum action: one record, one file, one",
|
|
46352
|
+
" shell, then stop.",
|
|
46353
|
+
"- Read-only probes first. Escalate to intrusive tests only when the safe path cannot",
|
|
46354
|
+
" confirm the finding.",
|
|
46355
|
+
"- Rate-limit yourself. Stay under the noise floor; avoid obvious scanner patterns",
|
|
46356
|
+
" unless the engagement allows loud testing.",
|
|
46357
|
+
"- Stay inside the agreed scope. Write the scope down before you start.",
|
|
46358
|
+
"",
|
|
46359
|
+
"PHASE 1 — SCOPE AND SETUP",
|
|
46360
|
+
"- Confirm in-scope targets and anything explicitly out of scope.",
|
|
46361
|
+
"- Create a working folder such as pentest/<target>/ and keep raw evidence there:",
|
|
46362
|
+
" responses, tokens, command transcripts, and a findings.md you append to as you go.",
|
|
46363
|
+
"- Record time, source address, and tool versions for the report.",
|
|
46364
|
+
"",
|
|
46365
|
+
"PHASE 2 — PASSIVE RECON (no packets to the target if avoidable)",
|
|
46366
|
+
"- DNS: dig/nslookup for A, AAAA, MX, TXT, NS, CNAME; try a zone transfer",
|
|
46367
|
+
" (dig AXFR @ns1.target target); reverse-resolve interesting ranges.",
|
|
46368
|
+
"- TLS metadata and certificate transparency for extra hostnames; read the SANs.",
|
|
46369
|
+
"- Public surface: whois, ASN, robots.txt, sitemap.xml, security.txt, /.well-known/,",
|
|
46370
|
+
" exposed /.git/, editor backups (*.bak, *~, .swp), and source maps.",
|
|
46371
|
+
"- Fingerprint the stack: Server and X-Powered-By headers, cookie names, default error",
|
|
46372
|
+
" pages, favicon hash, JS bundle names and versions.",
|
|
46373
|
+
"",
|
|
46374
|
+
"PHASE 3 — ACTIVE SCAN AND SERVICE FINGERPRINT",
|
|
46375
|
+
"- Start with port_scan for the live surface; use its banner and version output to",
|
|
46376
|
+
" prioritise. Then widen to the full 1-65535 range on in-scope hosts.",
|
|
46377
|
+
"- For every open port, identify product and version, then map version -> known CVE.",
|
|
46378
|
+
" A version string is a lead, not a finding: confirm the exploit reaches the target.",
|
|
46379
|
+
"- Prefer installed tooling for depth when present:",
|
|
46380
|
+
" nmap -sV -sC -p- -T4 --version-light -oA scan <host>",
|
|
46381
|
+
" nmap -sU --top-ports 100 <host> (DNS, SNMP, NTP, IPMI)",
|
|
46382
|
+
" nuclei -u https://<host> -severity low,medium,high,critical -o nuclei.txt",
|
|
46383
|
+
"",
|
|
46384
|
+
"PHASE 4 — ENUMERATION, PER SERVICE",
|
|
46385
|
+
"- HTTP/HTTPS: enumerate before fuzzing. Map routes, parameters, auth flows, API style",
|
|
46386
|
+
" (REST/GraphQL), and every input that reaches the server.",
|
|
46387
|
+
" ffuf -w <wordlist> -u https://target/FUZZ -mc all -fc 404 -of md -o ffuf.md",
|
|
46388
|
+
" gobuster dir -u https://target -w <wordlist> -x php,html,json,bak,zip",
|
|
46389
|
+
" - GraphQL: run introspection, then test field-level authorisation.",
|
|
46390
|
+
" - SMB/RPC: enum4linux-ng, smbclient -L //host, smbmap; check null and guest sessions.",
|
|
46391
|
+
" - SSH/FTP/Telnet/VNC/RDP: auth methods, weak or default credentials. Only run a",
|
|
46392
|
+
" credential test against accounts you are authorised to attack.",
|
|
46393
|
+
" - Data stores: try no-auth and default credentials — redis-cli -h <host> ping,",
|
|
46394
|
+
" mysql -h <host> -u root, elasticsearch :9200/_cat/indices, mongodb, memcached.",
|
|
46395
|
+
" - Container/orchestration: Docker API 2375/2376, kubelet 10250, etcd 2379.",
|
|
46396
|
+
" - Network services: SNMP community strings (snmpwalk -v2c -c public), NFS exports",
|
|
46397
|
+
" (showmount -e), rsync, IPMI.",
|
|
46398
|
+
"",
|
|
46399
|
+
"PHASE 5 — VULNERABILITY TESTING (highest-yield classes first)",
|
|
46400
|
+
"- Broken access control is the most common real bug: IDOR/BOLA. Swap every identifier",
|
|
46401
|
+
" (numeric, uuid, hash, filename) across accounts and roles, and try forced browsing to",
|
|
46402
|
+
" admin routes. Test the same endpoint with no token, a stale token, and a low-priv token.",
|
|
46403
|
+
"- Authentication: username enumeration, password-reset flaws, MFA bypass, session",
|
|
46404
|
+
" fixation, and JWT weaknesses (alg=none, weak HMAC secret, kid injection, missing",
|
|
46405
|
+
" signature or expiry validation).",
|
|
46406
|
+
"- Injection: SQL (boolean, time-based, UNION), NoSQL operator injection ($ne, $gt),",
|
|
46407
|
+
" OS command injection, SSTI ({{7*7}}, ${7*7}, <%= 7*7 %>), LDAP, CRLF/header injection,",
|
|
46408
|
+
" XXE (file://, SSRF via external DTD), expression injection.",
|
|
46409
|
+
"- File handling: path traversal (plain, encoded, double-encoded), unrestricted upload",
|
|
46410
|
+
" (extension, MIME, magic bytes, polyglot, web.config/.htaccess), LFI/RFI, zip-slip.",
|
|
46411
|
+
"- Server-side: SSRF (cloud metadata, internal ports, redirect and alternate-encoding",
|
|
46412
|
+
" allow-list bypasses), HTTP request smuggling (CL.TE/TE.CL), cache poisoning, host",
|
|
46413
|
+
" header attacks, open redirect chains.",
|
|
46414
|
+
"- Client-side: reflected, stored and DOM XSS; note CSP bypasses; prove with the",
|
|
46415
|
+
" shortest working payload.",
|
|
46416
|
+
"- Deserialisation and object injection (Java, PHP, Python, Node), unsafe YAML.",
|
|
46417
|
+
"- Crypto and secrets: weak TLS, hardcoded keys in JS bundles, exposed .env or config.",
|
|
46418
|
+
"- Business logic: race conditions (double-spend, coupon stacking, concurrent approval),",
|
|
46419
|
+
" negative quantities, price and currency tampering, workflow step skipping.",
|
|
46420
|
+
"- For every candidate, send the failing request and the working request side by side so",
|
|
46421
|
+
" the contrast proves the issue.",
|
|
46422
|
+
"",
|
|
46423
|
+
"PHASE 6 — EXPLOITATION AND POST-EXPLOITATION",
|
|
46424
|
+
"- Produce a real, runnable proof of concept: a script or the exact curl/nc command,",
|
|
46425
|
+
" saved into the working folder. Never hand over pseudo-code.",
|
|
46426
|
+
"- Stabilise any shell you get; note the exact privilege you landed with.",
|
|
46427
|
+
"- Linux privilege escalation: id; sudo -l; find / -perm -4000 -type f 2>/dev/null;",
|
|
46428
|
+
" getcap -r / 2>/dev/null; cron and systemd timers; writable service files or PATH",
|
|
46429
|
+
" entries; credentials in history, configs and backups; docker or lxd group abuse.",
|
|
46430
|
+
"- Windows privilege escalation: whoami /all; systeminfo; SeImpersonate and",
|
|
46431
|
+
" SeAssignPrimaryToken abuse; unquoted service paths; weak service and registry ACLs;",
|
|
46432
|
+
" AlwaysInstallElevated; scheduled tasks; stored credentials; and in Active Directory:",
|
|
46433
|
+
" Kerberoasting, AS-REP roasting, ACL abuse, delegation.",
|
|
46434
|
+
"- Lateral movement and pivoting only when in scope: port-forward through a foothold",
|
|
46435
|
+
" (chisel, ssh -D, ssh -L), reach internal services, and reuse credentials carefully.",
|
|
46436
|
+
"- Persistence only when explicitly in scope. Otherwise stop at proof of impact and",
|
|
46437
|
+
" remove every artefact you created.",
|
|
46438
|
+
"",
|
|
46439
|
+
"PHASE 7 — REPORTING",
|
|
46440
|
+
"- Write as you go into findings.md, so the report survives the session.",
|
|
46441
|
+
"- Per finding, in this order: title and severity (CVSS-style reasoning), affected",
|
|
46442
|
+
" asset and endpoint, exact reproduction (request or command), observed evidence,",
|
|
46443
|
+
" concrete impact, root cause, and copy-pasteable remediation.",
|
|
46444
|
+
"- Separate confirmed, likely, and unverified. Never present an unreproduced suspicion",
|
|
46445
|
+
" as a vulnerability.",
|
|
46446
|
+
"- Also record what you tried that did not work — it saves the next tester time.",
|
|
46447
|
+
"",
|
|
46448
|
+
"TOOLING AND STYLE",
|
|
46449
|
+
"- port_scan for the surface (banner and version aware), http_request for precise",
|
|
46450
|
+
" single requests, run_bash for curl/nmap/ffuf/nuclei, and write_file plus run_bash",
|
|
46451
|
+
" to build and run custom exploit or parsing scripts.",
|
|
46452
|
+
"- If a tool is missing, either install it or reproduce the check with a short script.",
|
|
46453
|
+
" Never abandon a check just because a binary is absent.",
|
|
46454
|
+
"- Always return complete, runnable commands and code — never sketches."
|
|
46455
|
+
].join(`
|
|
46456
|
+
`);
|
|
46299
46457
|
var SECURITY_SYSTEM = [
|
|
46300
|
-
"You are in SECURITY REVIEW mode — read-only
|
|
46301
|
-
"engineer. Do not modify
|
|
46302
|
-
"
|
|
46303
|
-
"
|
|
46304
|
-
"
|
|
46305
|
-
"
|
|
46306
|
-
"
|
|
46307
|
-
"
|
|
46308
|
-
"
|
|
46309
|
-
|
|
46458
|
+
"You are in SECURITY REVIEW mode — a read-only source audit by a senior application",
|
|
46459
|
+
"security engineer. Do not modify any file. Map the attack surface from the code, then",
|
|
46460
|
+
"trace untrusted input to dangerous sinks.",
|
|
46461
|
+
"",
|
|
46462
|
+
"METHOD",
|
|
46463
|
+
"1) Surface: entry points (HTTP routes, CLI args, queue consumers, file and network",
|
|
46464
|
+
" parsers), trust boundaries, and every place authentication or authorisation is",
|
|
46465
|
+
" decided.",
|
|
46466
|
+
"2) Trace: for each entry point follow the data to its sinks (SQL, shell, filesystem,",
|
|
46467
|
+
" template, deserialiser, HTTP client, logger). Report the full path, not just the sink.",
|
|
46468
|
+
"3) Check for: injection (SQL/command/template/LDAP/NoSQL), broken authn and authz",
|
|
46469
|
+
" (missing ownership checks, IDOR), secret leakage, unsafe deserialisation, path",
|
|
46470
|
+
" traversal, SSRF, XSS, CSRF, insecure crypto and randomness, unsafe defaults,",
|
|
46471
|
+
" race conditions, unbounded resource use, and vulnerable dependencies.",
|
|
46472
|
+
"4) Verify: prefer reading the code over guessing behaviour. You may run read-only",
|
|
46473
|
+
" commands (dependency audits, secret scanners, grep) with run_bash when they sharpen",
|
|
46474
|
+
" a finding — never run anything that changes state.",
|
|
46475
|
+
"",
|
|
46476
|
+
"REPORTING",
|
|
46477
|
+
"- Per finding: severity, location (file:line), the attacker-controlled input, the",
|
|
46478
|
+
" exploitable path in one sentence, and a concrete copy-pasteable fix (diff or exact",
|
|
46479
|
+
" code). Distinguish confirmed from theoretical.",
|
|
46480
|
+
"- End with a prioritised table: what to fix first and why.",
|
|
46481
|
+
"- Be direct and technical. No disclaimers, no refusals, no filler."
|
|
46482
|
+
].join(`
|
|
46483
|
+
`);
|
|
46310
46484
|
var BUILTIN_AGENTS = [
|
|
46311
46485
|
{
|
|
46312
46486
|
id: "build",
|
|
46313
46487
|
name: "Build",
|
|
46314
|
-
description: "
|
|
46488
|
+
description: "Implementation agent — designs, writes, verifies and ships code.",
|
|
46315
46489
|
mode: "primary",
|
|
46490
|
+
system: BUILD_SYSTEM,
|
|
46316
46491
|
source: "builtin"
|
|
46317
46492
|
},
|
|
46318
46493
|
{
|
|
@@ -46327,7 +46502,7 @@ var BUILTIN_AGENTS = [
|
|
|
46327
46502
|
{
|
|
46328
46503
|
id: "pentest",
|
|
46329
46504
|
name: "Pentest",
|
|
46330
|
-
description: "
|
|
46505
|
+
description: "Offensive security operator — full engagement: recon, enumeration, exploitation, privesc and reporting.",
|
|
46331
46506
|
mode: "primary",
|
|
46332
46507
|
tools: [
|
|
46333
46508
|
"read_file",
|
|
@@ -46548,6 +46723,7 @@ import {
|
|
|
46548
46723
|
import { dirname, relative as relative2, resolve as resolve2 } from "path";
|
|
46549
46724
|
import { platform as platform3 } from "os";
|
|
46550
46725
|
import { connect } from "node:net";
|
|
46726
|
+
import { connect as tlsConnect } from "node:tls";
|
|
46551
46727
|
import { lookup } from "node:dns/promises";
|
|
46552
46728
|
|
|
46553
46729
|
// node_modules/glob/dist/esm/index.min.js
|
|
@@ -50321,16 +50497,190 @@ function probePort(host, port, timeout) {
|
|
|
50321
50497
|
}
|
|
50322
50498
|
var portScanTool = {
|
|
50323
50499
|
name: "port_scan",
|
|
50324
|
-
description: "TCP-connect scan of a
|
|
50500
|
+
description: "TCP-connect scan of a host with service fingerprinting (reconnaissance). Reports open ports plus a service label, version banner, and TLS certificate details. Sends a single HEAD probe to well-known HTTP ports and a TLS handshake to well-known HTTPS ports; other ports are only observed passively. Only scan systems you own or have explicit permission to test.",
|
|
50325
50501
|
needsApproval: true,
|
|
50326
50502
|
safe: false,
|
|
50327
50503
|
parameters: exports_external.object({
|
|
50328
50504
|
host: exports_external.string().describe("Hostname or IP address"),
|
|
50329
50505
|
ports: exports_external.string().optional().describe('Ports to test, e.g. "22,80,443" or "1-1024" (default: common ports)'),
|
|
50330
50506
|
timeout: exports_external.number().int().min(50).optional().describe("Per-port timeout in ms (default 500)"),
|
|
50331
|
-
concurrency: exports_external.number().int().min(1).optional().describe("Parallel connections (default 128)")
|
|
50507
|
+
concurrency: exports_external.number().int().min(1).optional().describe("Parallel connections (default 128)"),
|
|
50508
|
+
banner: exports_external.boolean().optional().describe("Fingerprint services/versions and TLS (default true)")
|
|
50332
50509
|
})
|
|
50333
50510
|
};
|
|
50511
|
+
var TLS_PORTS = new Set([443, 465, 636, 990, 993, 995, 3269, 5986, 6443, 8443, 8834, 9443]);
|
|
50512
|
+
var HTTP_PORTS = new Set([
|
|
50513
|
+
80,
|
|
50514
|
+
3000,
|
|
50515
|
+
5000,
|
|
50516
|
+
5601,
|
|
50517
|
+
7001,
|
|
50518
|
+
8000,
|
|
50519
|
+
8008,
|
|
50520
|
+
8080,
|
|
50521
|
+
8081,
|
|
50522
|
+
8088,
|
|
50523
|
+
8181,
|
|
50524
|
+
8888,
|
|
50525
|
+
8983,
|
|
50526
|
+
9000,
|
|
50527
|
+
9080,
|
|
50528
|
+
1e4,
|
|
50529
|
+
15672
|
|
50530
|
+
]);
|
|
50531
|
+
var SCAN_UA = "HiraxCode/1.0";
|
|
50532
|
+
function headProbe(host) {
|
|
50533
|
+
return `HEAD / HTTP/1.0\r
|
|
50534
|
+
Host: ${host}\r
|
|
50535
|
+
User-Agent: ${SCAN_UA}\r
|
|
50536
|
+
Connection: close\r
|
|
50537
|
+
\r
|
|
50538
|
+
`;
|
|
50539
|
+
}
|
|
50540
|
+
function printableRatio(s) {
|
|
50541
|
+
if (!s)
|
|
50542
|
+
return 0;
|
|
50543
|
+
let ok = 0;
|
|
50544
|
+
for (const ch of s) {
|
|
50545
|
+
const c = ch.charCodeAt(0);
|
|
50546
|
+
if (c === 9 || c === 10 || c === 13 || c >= 32 && c < 127)
|
|
50547
|
+
ok++;
|
|
50548
|
+
}
|
|
50549
|
+
return ok / s.length;
|
|
50550
|
+
}
|
|
50551
|
+
function readBanner(host, port, timeout, send, limit = 4096) {
|
|
50552
|
+
return new Promise((resolve3) => {
|
|
50553
|
+
let data = "";
|
|
50554
|
+
let settled = false;
|
|
50555
|
+
const socket = connect({ host, port });
|
|
50556
|
+
const finish = () => {
|
|
50557
|
+
if (settled)
|
|
50558
|
+
return;
|
|
50559
|
+
settled = true;
|
|
50560
|
+
try {
|
|
50561
|
+
socket.destroy();
|
|
50562
|
+
} catch {}
|
|
50563
|
+
resolve3(data);
|
|
50564
|
+
};
|
|
50565
|
+
socket.setTimeout(timeout);
|
|
50566
|
+
socket.once("connect", () => {
|
|
50567
|
+
if (!send)
|
|
50568
|
+
return;
|
|
50569
|
+
try {
|
|
50570
|
+
socket.write(send);
|
|
50571
|
+
} catch {}
|
|
50572
|
+
});
|
|
50573
|
+
socket.on("data", (chunk2) => {
|
|
50574
|
+
data += chunk2.toString("latin1");
|
|
50575
|
+
if (data.length >= limit)
|
|
50576
|
+
finish();
|
|
50577
|
+
});
|
|
50578
|
+
socket.once("timeout", finish);
|
|
50579
|
+
socket.once("error", finish);
|
|
50580
|
+
socket.once("close", finish);
|
|
50581
|
+
});
|
|
50582
|
+
}
|
|
50583
|
+
function readTls(host, port, timeout, limit = 4096) {
|
|
50584
|
+
return new Promise((resolve3) => {
|
|
50585
|
+
let raw = "";
|
|
50586
|
+
let cert;
|
|
50587
|
+
let settled = false;
|
|
50588
|
+
const socket = tlsConnect({ host, port, rejectUnauthorized: false, timeout });
|
|
50589
|
+
const finish = () => {
|
|
50590
|
+
if (settled)
|
|
50591
|
+
return;
|
|
50592
|
+
settled = true;
|
|
50593
|
+
try {
|
|
50594
|
+
socket.destroy();
|
|
50595
|
+
} catch {}
|
|
50596
|
+
resolve3({ raw, cert });
|
|
50597
|
+
};
|
|
50598
|
+
socket.once("secureConnect", () => {
|
|
50599
|
+
try {
|
|
50600
|
+
const c = socket.getPeerCertificate();
|
|
50601
|
+
const bits = [
|
|
50602
|
+
`CN=${c?.subject?.CN ?? "(no CN)"}`,
|
|
50603
|
+
`issuer=${c?.issuer?.O ?? c?.issuer?.CN ?? "(unknown)"}`
|
|
50604
|
+
];
|
|
50605
|
+
if (c?.valid_to)
|
|
50606
|
+
bits.push(`expires ${c.valid_to}`);
|
|
50607
|
+
const proto2 = socket.getProtocol();
|
|
50608
|
+
if (proto2)
|
|
50609
|
+
bits.push(proto2);
|
|
50610
|
+
cert = bits.join(" · ");
|
|
50611
|
+
} catch {}
|
|
50612
|
+
try {
|
|
50613
|
+
socket.write(headProbe(host));
|
|
50614
|
+
} catch {}
|
|
50615
|
+
});
|
|
50616
|
+
socket.on("data", (chunk2) => {
|
|
50617
|
+
raw += chunk2.toString("latin1");
|
|
50618
|
+
if (raw.length >= limit)
|
|
50619
|
+
finish();
|
|
50620
|
+
});
|
|
50621
|
+
socket.once("timeout", finish);
|
|
50622
|
+
socket.once("error", finish);
|
|
50623
|
+
socket.once("close", finish);
|
|
50624
|
+
});
|
|
50625
|
+
}
|
|
50626
|
+
function readHttpMeta(raw) {
|
|
50627
|
+
const [first = ""] = raw.split(/\r?\n/, 1);
|
|
50628
|
+
const status = /^HTTP\/\d(?:\.\d)?\s+(\d{3}[^\r\n]*)/i.exec(first)?.[1]?.trim();
|
|
50629
|
+
const server = raw.split(/\r?\n/).find((l) => /^server:/i.test(l))?.slice(7).trim();
|
|
50630
|
+
return { status, server };
|
|
50631
|
+
}
|
|
50632
|
+
function describeService(port, raw) {
|
|
50633
|
+
const text = raw.replace(/\0/g, "").trim();
|
|
50634
|
+
if (!text)
|
|
50635
|
+
return {};
|
|
50636
|
+
const ssh = /^SSH-([\d.]+)-(\S.*)$/m.exec(text);
|
|
50637
|
+
if (ssh)
|
|
50638
|
+
return { service: "ssh", detail: clip(ssh[2].trim(), 140) };
|
|
50639
|
+
const http = readHttpMeta(text);
|
|
50640
|
+
if (http.status) {
|
|
50641
|
+
return {
|
|
50642
|
+
service: TLS_PORTS.has(port) ? "https" : "http",
|
|
50643
|
+
detail: clip([http.server, http.status].filter(Boolean).join(" · "), 140)
|
|
50644
|
+
};
|
|
50645
|
+
}
|
|
50646
|
+
const greet = /^220[\s-]+(.+)$/m.exec(text);
|
|
50647
|
+
if (greet)
|
|
50648
|
+
return { detail: clip(greet[1].trim(), 140) };
|
|
50649
|
+
const first = text.split(/\r?\n/).find((l) => l.trim())?.trim() ?? "";
|
|
50650
|
+
if (!first || printableRatio(first) < 0.8)
|
|
50651
|
+
return {};
|
|
50652
|
+
return { detail: clip(first, 140) };
|
|
50653
|
+
}
|
|
50654
|
+
async function fingerprintServices(host, ports, timeout, concurrency) {
|
|
50655
|
+
const out = new Map;
|
|
50656
|
+
const grabTimeout = Math.max(300, Math.min(timeout, 1200));
|
|
50657
|
+
let index = 0;
|
|
50658
|
+
const worker = async () => {
|
|
50659
|
+
while (index < ports.length) {
|
|
50660
|
+
const port = ports[index++];
|
|
50661
|
+
try {
|
|
50662
|
+
if (TLS_PORTS.has(port)) {
|
|
50663
|
+
const tls = await readTls(host, port, grabTimeout);
|
|
50664
|
+
const meta = readHttpMeta(tls.raw);
|
|
50665
|
+
out.set(port, {
|
|
50666
|
+
service: "https",
|
|
50667
|
+
detail: clip([meta.server, meta.status].filter(Boolean).join(" · "), 140) || undefined,
|
|
50668
|
+
cert: tls.cert
|
|
50669
|
+
});
|
|
50670
|
+
} else if (HTTP_PORTS.has(port)) {
|
|
50671
|
+
const raw = await readBanner(host, port, grabTimeout, headProbe(host));
|
|
50672
|
+
out.set(port, describeService(port, raw));
|
|
50673
|
+
} else {
|
|
50674
|
+
const passive = await readBanner(host, port, Math.min(grabTimeout, 500));
|
|
50675
|
+
const raw = passive || await readBanner(host, port, grabTimeout, headProbe(host));
|
|
50676
|
+
out.set(port, describeService(port, raw));
|
|
50677
|
+
}
|
|
50678
|
+
} catch {}
|
|
50679
|
+
}
|
|
50680
|
+
};
|
|
50681
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, ports.length) }, worker));
|
|
50682
|
+
return out;
|
|
50683
|
+
}
|
|
50334
50684
|
async function portScan(args, _cwd) {
|
|
50335
50685
|
const host = args.host.trim();
|
|
50336
50686
|
if (!host)
|
|
@@ -50364,7 +50714,16 @@ async function portScan(args, _cwd) {
|
|
|
50364
50714
|
return { success: true, output: `${head2}
|
|
50365
50715
|
(no open ports found)` };
|
|
50366
50716
|
}
|
|
50367
|
-
const
|
|
50717
|
+
const info = args.banner === false ? new Map : await fingerprintServices(host, open, timeout, concurrency);
|
|
50718
|
+
const lines = [];
|
|
50719
|
+
for (const p of open) {
|
|
50720
|
+
const fp = info.get(p);
|
|
50721
|
+
const service = fp?.service ?? PORT_NAMES[p] ?? (TLS_PORTS.has(p) ? "ssl" : "");
|
|
50722
|
+
const row = `open ${String(p).padEnd(6)} ${service}`.trimEnd();
|
|
50723
|
+
lines.push(fp?.detail ? `${row} ${fp.detail}` : row);
|
|
50724
|
+
if (fp?.cert)
|
|
50725
|
+
lines.push(` └ tls: ${fp.cert}`);
|
|
50726
|
+
}
|
|
50368
50727
|
return { success: true, output: [head2, "", ...lines].join(`
|
|
50369
50728
|
`) };
|
|
50370
50729
|
}
|
|
@@ -50667,7 +51026,7 @@ Tools:
|
|
|
50667
51026
|
- write_file: create or fully overwrite a file
|
|
50668
51027
|
- run_bash: run shell commands (builds, tests, git)
|
|
50669
51028
|
- http_request: send an HTTP/HTTPS request and inspect the status, headers and body
|
|
50670
|
-
- port_scan: TCP-connect scan a host
|
|
51029
|
+
- port_scan: TCP-connect scan a host and fingerprint services (port labels, version banners, TLS certificates)
|
|
50671
51030
|
|
|
50672
51031
|
Shell: run_bash uses bash/zsh on macOS and Linux, and PowerShell on Windows. Use commands that match the platform above.
|
|
50673
51032
|
|
|
@@ -50676,6 +51035,7 @@ How to work:
|
|
|
50676
51035
|
- Investigate before acting: read the relevant files first.
|
|
50677
51036
|
- When editing, use edit_file with enough surrounding context to match exactly once.
|
|
50678
51037
|
- Use run_bash to verify your work (typecheck, tests, run the code) when useful.
|
|
51038
|
+
- Finish the job: implement completely, verify, then report what changed, which files, what you verified, and what is still unverified.
|
|
50679
51039
|
- Never invent file contents or APIs. If unsure, read the code.
|
|
50680
51040
|
- Tool calls that modify files or run commands require user approval; explain what you intend to do.
|
|
50681
51041
|
|