Compare commits

...

6 commits

Author SHA1 Message Date
85ad7f7387 Merge pull request 'Redesign home command deck' (#13) from frontend-redesign into main
Some checks are pending
CI / Validate (push) Waiting to run
Reviewed-on: #13
2026-05-28 16:21:31 +00:00
bb87343b7f Merge branch 'main' into frontend-redesign
Some checks failed
CI / Validate (pull_request) Has been cancelled
2026-05-28 09:15:56 +00:00
47a5adca90 Add attack surface audit artifacts
Some checks failed
CI / Validate (pull_request) Has been cancelled
- Add advisory, entrypoint, and candidate scan outputs
- Capture dependency intelligence and cross-service attack surface notes
2026-05-28 05:13:36 -04:00
a35a757622 Redesign home command deck 2026-05-28 05:10:21 -04:00
b075a0994c Add dashboard mock routes 2026-05-28 04:40:10 -04:00
ffbdbc3376 docs: add May 24 standup git summary 2026-05-25 09:04:56 -04:00
38 changed files with 5905 additions and 27 deletions

View file

@ -1,3 +1,4 @@
{"_type":"issue","id":"islandflow-2op","title":"[bug] Desktop app unclickable and no live data in hosted shell","description":"## Summary\\nDesktop Electron shell appears fully non-interactive (clicks do not work) and no live market data reaches the UI.\\n\\n## Why this matters\\nDesktop wrapper is currently unusable for core workflow and blocks users from validating market streams outside browser.\\n\\n## Scope\\nReproduce issue locally, identify root cause(s) in Electron shell and frontend integration, implement fix, and validate interactivity + data flow end-to-end.\\n\\n## Acceptance Criteria\\n- Desktop app responds to pointer interactions (navigation/actions clickable)\\n- Live data stream connects and updates UI in desktop mode\\n- Regression coverage or guardrails added where practical\\n- Findings and validation documented","status":"in_progress","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-24T04:23:55Z","created_by":"dirtydishes","updated_at":"2026-05-24T04:23:57Z","started_at":"2026-05-24T04:23:57Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-jad","title":"Sync docs pages workflow fix to github mirror","description":"GitHub is still running an older docs Pages workflow with configure-pages because github/main is behind forgejo/main. Push the already-fixed workflow commit to the GitHub mirror so Actions runs the gh-pages branch deployment flow instead.","status":"closed","priority":1,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-23T22:27:46Z","created_by":"dirtydishes","updated_at":"2026-05-23T22:28:24Z","started_at":"2026-05-23T22:28:10Z","closed_at":"2026-05-23T22:28:24Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-bc7","title":"Fix docs Pages workflow configure-pages failure","description":"Replace the current docs Pages deployment flow so workflow runs succeed even when configure-pages cannot read or enable the site. Keep published docs target behavior for dirtydishes.github.io/islandflow/docs.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-23T22:23:28Z","created_by":"dirtydishes","updated_at":"2026-05-23T22:25:19Z","started_at":"2026-05-23T22:23:31Z","closed_at":"2026-05-23T22:25:19Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-3o0","title":"address forgejo issue #10 security dependency cves","description":"Track remediation for Forgejo issue #10 (2026-05-23 security CVE triage): upgrade dependency chain to resolve tar/ws/postcss/tmp advisories, validate with bun audit and relevant quality gates.","status":"closed","priority":1,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-23T16:59:34Z","created_by":"dirtydishes","updated_at":"2026-05-23T17:03:06Z","started_at":"2026-05-23T16:59:38Z","closed_at":"2026-05-23T17:03:06Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
@ -23,6 +24,8 @@
{"_type":"issue","id":"islandflow-ayo","title":"Drop stale backlog events from live fanout","description":"Follow-up to live freshness rollout: /ws/live was still fanning out stale backlog events for freshness-gated channels, which kept tape panes in Live feed behind despite active synthetic ingest. Gate fanout and cache ingest by freshness for options/nbbo/equities/flow.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-04-28T21:26:39Z","created_by":"dirtydishes","updated_at":"2026-04-28T21:26:44Z","started_at":"2026-04-28T21:26:44Z","closed_at":"2026-04-28T21:26:44Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-0v6","title":"Fix tape freshness, NBBO coverage, pause controls, and filter popup","description":"Implement the tape fixes requested for synthetic options notional sizing, strict live freshness, live-mode pause/resume behavior, stronger NBBO snapshot coverage, and moving flow filters behind a popup. Includes server-side live cache changes, web terminal state/UI changes, and tests for synthetic pricing, live snapshot freshness/NBBO retention, and live pause/filter interactions.","status":"closed","priority":1,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-04-28T21:02:52Z","created_by":"dirtydishes","updated_at":"2026-04-28T21:13:38Z","started_at":"2026-04-28T21:02:57Z","closed_at":"2026-04-28T21:13:38Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-e4r","title":"Implement smart-money flow filtering and synthetic firehose modes","description":"Implement the approved multi-surface plan for named synthetic market profiles, options raw-vs-signal filtering, live/API filter contracts, Tape page client-side flow filters, firehose-readiness improvements, tests, and README updates.","status":"closed","priority":1,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-04-28T20:10:49Z","created_by":"dirtydishes","updated_at":"2026-04-28T20:29:29Z","started_at":"2026-04-28T20:10:53Z","closed_at":"2026-04-28T20:29:29Z","close_reason":"Implemented synthetic market profiles, options signal-path filtering, signal-aware API/replay contracts, Tape page filters, tests, and README updates. Follow-up tracked in islandflow-biq.","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-ddm","title":"Redesign home as command deck","description":"Implement the mock1-inspired production command deck on / while preserving focused /options and /news workspaces plus existing legacy redirects. Scope includes apps/web terminal layout, production command-deck CSS, validation, turn documentation, and Forgejo publish.","notes":"Scope: redesign / as a mock1-inspired production command deck using live useTerminal state and existing panes; preserve /options, /news, /mock1, and current legacy redirects. Leave unrelated apps/web/next-env.d.ts and piolium/ changes untouched.","status":"closed","priority":2,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-28T08:59:14Z","created_by":"dirtydishes","updated_at":"2026-05-28T09:09:43Z","started_at":"2026-05-28T08:59:29Z","closed_at":"2026-05-28T09:09:43Z","close_reason":"Implemented / as a mock1-inspired production command deck using live terminal state, preserved focused /options and /news routes plus legacy redirects, validated tests/build/screenshots, and documented the turn.","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-4xb","title":"Create dashboard structure mock routes","description":"Prototype four alternate islandflow dashboard structures at /mock1 through /mock4 based on the supplied reference so the main dashboard direction can be evaluated live.","status":"closed","priority":2,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-28T08:30:33Z","created_by":"dirtydishes","updated_at":"2026-05-28T08:38:35Z","started_at":"2026-05-28T08:30:39Z","closed_at":"2026-05-28T08:38:35Z","close_reason":"Added four dashboard mock routes, documented the implementation, and validated build/tests plus route responses.","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-1gq","title":"Set up Forgejo-native CI baseline","description":"Create a Forgejo-native CI workflow under .forgejo/workflows that runs the existing fast, high-signal validation checks on pull requests, pushes to main, and manual dispatch. Document the runner label expectations, scope of the job, and manual rerun path in repository docs. Keep heavier container/integration work out of the initial PR gate.","status":"closed","priority":2,"issue_type":"task","owner":"dishes@dpdrm.com","created_at":"2026-05-24T00:31:55Z","created_by":"dirtydishes","updated_at":"2026-05-24T00:36:03Z","closed_at":"2026-05-24T00:36:03Z","close_reason":"Implemented a Forgejo-native CI baseline under .forgejo/workflows, documented runner expectations in the README, and synced the docker workspace snapshot so the fast validate path passes.","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-7ez","title":"rename tape to options and replace web rail with drawer shell","description":"Implement the web and desktop route transition from /tape to /options, keep /tape as a compatibility redirect, replace the persistent web rail with a shared sticky header plus overlay drawer, and update validation/docs to match.","status":"closed","priority":2,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-23T23:30:06Z","created_by":"dirtydishes","updated_at":"2026-05-23T23:38:59Z","started_at":"2026-05-23T23:30:24Z","closed_at":"2026-05-23T23:38:59Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-hoh","title":"clarify turn-doc exemptions and ambiguity rule","description":"Update AGENTS.md turn documentation rules so minor/trivial checklist takes precedence, ambiguous cases require user check-in, and completion rule applies only when turn docs are required.","status":"closed","priority":2,"issue_type":"task","owner":"dishes@dpdrm.com","created_at":"2026-05-23T23:02:10Z","created_by":"dirtydishes","updated_at":"2026-05-23T23:02:30Z","closed_at":"2026-05-23T23:02:30Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
@ -72,7 +75,7 @@
{"_type":"issue","id":"islandflow-dod","title":"Publish terminal audit to GitHub Pages","description":"Why this issue exists and what needs to be done: publish the generated terminal audit HTML to dirtydishes.github.io at /terminal-audit.html so it can be shared publicly.","status":"closed","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-14T08:39:45Z","created_by":"dirtydishes","updated_at":"2026-05-14T08:42:59Z","started_at":"2026-05-14T08:40:02Z","closed_at":"2026-05-14T08:42:59Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-dxu","title":"Document terminal audit findings as HTML","description":"Why this issue exists and what needs to be done: capture the completed terminal view audit findings in a user-readable HTML document under docs/ with the full score summary and all detailed findings preserved.","status":"closed","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-14T08:32:22Z","created_by":"dirtydishes","updated_at":"2026-05-14T08:34:57Z","started_at":"2026-05-14T08:32:30Z","closed_at":"2026-05-14T08:34:57Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-a50","title":"Add HTML plan docs for synthetic tape redesign","description":"Create two HTML planning docs under plans/: one straightforward end-user readable version and one more polished impeccable-style version, both covering the hosted synthetic tape redesign with summary, scope, affected services, UI notes, rollout, tests, and the full detailed implementation plan.\n","status":"closed","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-14T02:47:44Z","created_by":"dirtydishes","updated_at":"2026-05-14T02:53:11Z","started_at":"2026-05-14T02:47:48Z","closed_at":"2026-05-14T02:53:11Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-932","title":"Desktop follow-up native features","description":"Track deferred native desktop features after the thin hosted-wrapper v1 lands: notifications, keyboard shortcuts, local preferences storage, remembered window state, signed/notarized macOS distribution, auto-update evaluation, and optional local frontend bundling.\n","status":"open","priority":2,"issue_type":"task","owner":"dishes@dpdrm.com","created_at":"2026-05-13T13:20:12Z","created_by":"dirtydishes","updated_at":"2026-05-13T13:20:12Z","dependencies":[{"issue_id":"islandflow-932","depends_on_id":"islandflow-9ug","type":"discovered-from","created_at":"2026-05-13T09:20:12Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-932","title":"Desktop follow-up native features","description":"Track deferred native desktop features after the thin hosted-wrapper v1 lands: notifications, keyboard shortcuts, local preferences storage, remembered window state, signed/notarized macOS distribution, auto-update evaluation, and optional local frontend bundling.\n","status":"in_progress","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-13T13:20:12Z","created_by":"dirtydishes","updated_at":"2026-05-24T04:23:46Z","started_at":"2026-05-24T04:23:46Z","dependencies":[{"issue_id":"islandflow-932","depends_on_id":"islandflow-9ug","type":"discovered-from","created_at":"2026-05-13T09:20:12Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-vbk","title":"Remove deprecated Alpaca key-pair auth","description":"Remove legacy Alpaca key-pair authentication support and keep ALPACA_API_KEY as the only supported auth method across options/equities ingest and docs.\n","status":"closed","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-05T07:19:51Z","created_by":"dirtydishes","updated_at":"2026-05-05T07:21:10Z","started_at":"2026-05-05T07:19:54Z","closed_at":"2026-05-05T07:21:10Z","close_reason":"Removed key-pair auth and kept ALPACA_API_KEY only","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-h47","title":"Support single-token Alpaca auth","description":"Support single-token Alpaca authentication across ingest adapters using ALPACA_API_KEY with fallback to ALPACA_KEY_ID/ALPACA_SECRET_KEY, and document env usage.\n","status":"closed","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-05T07:12:22Z","created_by":"dirtydishes","updated_at":"2026-05-05T07:13:54Z","started_at":"2026-05-05T07:12:25Z","closed_at":"2026-05-05T07:13:54Z","close_reason":"Added ALPACA_API_KEY support with key-pair fallback","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-neu","title":"Add Alpha Vantage event calendar provider","description":"Add an Alpha Vantage earnings-calendar provider to services/refdata that fetches CSV, normalizes entries, writes the JSON cache consumed by compute, and documents the required env variables.\n","status":"closed","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-05T07:00:31Z","created_by":"dirtydishes","updated_at":"2026-05-05T07:02:30Z","started_at":"2026-05-05T07:00:37Z","closed_at":"2026-05-05T07:02:30Z","close_reason":"Added Alpha Vantage event-calendar provider","dependency_count":0,"dependent_count":0,"comment_count":0}
@ -97,3 +100,4 @@
{"_type":"issue","id":"islandflow-zsy","title":"Expose Forgejo SSH on a direct DNS hostname","description":"git.deltaisland.io currently resolves through Cloudflare's proxy, so SSH on port 2222 does not complete even though the Forgejo container is listening on the host. If SSH-based git/beads workflows are desired, add a DNS-only hostname (or adjust the existing record) that points directly at the server for Forgejo SSH.","status":"open","priority":3,"issue_type":"task","created_at":"2026-05-17T10:34:06Z","created_by":"delta","updated_at":"2026-05-17T10:34:06Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-38p","title":"Add native deployment unit templates and rollback helpers","description":"The deploy helper now supports --runtime native, but the repo still relies on operator-managed systemd units and manual rollback. Add checked-in native deployment templates or provisioning guidance for the expected units, and consider lightweight rollback/smoke-test helpers once the host-native path is exercised on the real VPS.","status":"open","priority":3,"issue_type":"task","owner":"dishes@dpdrm.com","created_at":"2026-05-15T23:46:42Z","created_by":"dirtydishes","updated_at":"2026-05-15T23:46:42Z","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-575","title":"Document smart-money event calendar env","description":"Document smart-money event-calendar environment configuration in env examples and README.\n","status":"closed","priority":3,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-05T06:57:14Z","created_by":"dirtydishes","updated_at":"2026-05-05T06:57:57Z","started_at":"2026-05-05T06:57:17Z","closed_at":"2026-05-05T06:57:57Z","close_reason":"Documented event-calendar env variables","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-1tu","title":"Publish 2026-05-24 standup summary","description":"Why this issue exists and what needs to be done\n\nCreate the daily standup summary for git activity on 2026-05-24, grounded in commits and touched files, then store the HTML report in docs/general.","status":"closed","priority":4,"issue_type":"task","owner":"dishes@dpdrm.com","created_at":"2026-05-25T13:02:56Z","created_by":"dirtydishes","updated_at":"2026-05-25T13:04:31Z","closed_at":"2026-05-25T13:04:31Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}

View file

@ -0,0 +1,458 @@
import Link from "next/link";
import type { CSSProperties, ReactNode } from "react";
type MockVariant = "mock1" | "mock2" | "mock3" | "mock4";
type DashboardMockProps = {
variant: MockVariant;
};
const variants: Record<
MockVariant,
{
title: string;
premise: string;
mode: string;
layout: string;
}
> = {
mock1: {
title: "Command Deck",
premise: "Closest to the reference: left navigation, ticker ribbon, dense evidence panes, replay rail.",
mode: "Dense ops",
layout: "classic"
},
mock2: {
title: "Investigation Stack",
premise: "A calmer analyst layout with the selected symbol story in the center and context wrapped around it.",
mode: "Forensic",
layout: "focus"
},
mock3: {
title: "Signal Wall",
premise: "Prioritizes alert triage and cross-symbol scanning before a user drills into price action.",
mode: "Triage",
layout: "signals"
},
mock4: {
title: "Replay Lab",
premise: "A replay-first structure with timeline, event tape, and causality context always visible.",
mode: "Replay",
layout: "replay"
}
};
const tickers = [
["SPY", "529.18", "+0.23%", "up"],
["QQQ", "452.47", "+0.31%", "up"],
["AAPL", "194.88", "+1.22%", "up"],
["NVDA", "120.19", "-0.41%", "down"],
["TSLA", "180.72", "+0.72%", "up"],
["AMZN", "186.31", "+0.35%", "up"],
["IWM", "205.41", "+0.21%", "up"]
];
const optionRows = [
["2m", "AAPL", "May 17", "195 C", "5,240", "$2.31M", "Sweep", "Bullish"],
["3m", "AAPL", "Jun 21", "200 C", "6,800", "$1.87M", "Block", "Bullish"],
["4m", "NVDA", "May 24", "120 C", "9,150", "$2.01M", "Split", "Bullish"],
["5m", "TSLA", "Jul 19", "205 C", "10,000", "$3.45M", "Block", "Bullish"],
["6m", "AMZN", "May 17", "185 P", "4,500", "$1.20M", "Sweep", "Bearish"],
["7m", "IWM", "Jun 21", "207 C", "3,100", "$712K", "Sweep", "Bullish"],
["8m", "AAPL", "May 24", "197.5 C", "7,600", "$2.01M", "Block", "Bullish"]
];
const signals = [
["09:41:10", "Dark Flow Sweep", "AAPL", "$4.32M", "Bullish"],
["09:40:58", "Unusual Options Activity", "NVDA", "$2.01M", "Bullish"],
["09:40:21", "News Catalyst", "AAPL", "AI update", "News"],
["09:39:47", "Classifier Hit: Momentum", "TSLA", "91%", "Bullish"],
["09:39:12", "Large Block Trade", "AMZN", "$3.67M", "Bearish"]
];
const feedHealth = [
["OPRA Options", "Healthy", "120ms", "2,341"],
["CBOE Quotes", "Healthy", "85ms", "1,987"],
["Nasdaq TotalView", "Healthy", "92ms", "3,102"],
["NYSE Pillar", "Degraded", "412ms", "932"],
["News", "Healthy", "1.2s", "12"],
["Dark Pool", "Healthy", "1.0s", "421"]
];
const darkFlow = [
["09:41:05", "AAPL", "Buy", "25,000", "$4.87M", "Sweep"],
["09:40:51", "AAPL", "Buy", "18,500", "$3.60M", "Sweep"],
["09:40:35", "AAPL", "Sell", "30,000", "$5.84M", "Block"],
["09:39:59", "AAPL", "Buy", "12,000", "$2.34M", "Sweep"],
["09:38:47", "AAPL", "Sell", "21,000", "$4.09M", "Block"]
];
const variantOrder: MockVariant[] = ["mock1", "mock2", "mock3", "mock4"];
export function DashboardMock({ variant }: DashboardMockProps) {
const config = variants[variant];
return (
<section className={`mock-terminal mock-terminal-${config.layout}`} aria-labelledby="mock-title">
<MockHeader config={config} active={variant} />
<TickerRail />
{variant === "mock1" ? <ClassicLayout /> : null}
{variant === "mock2" ? <FocusLayout /> : null}
{variant === "mock3" ? <SignalLayout /> : null}
{variant === "mock4" ? <ReplayLayout /> : null}
</section>
);
}
function MockHeader({
config,
active
}: {
config: (typeof variants)[MockVariant];
active: MockVariant;
}) {
return (
<header className="mock-header">
<div className="mock-brand-lockup">
<span className="mock-mark" aria-hidden="true" />
<div>
<span className="mock-brand">islandflow</span>
<h1 id="mock-title">{config.title}</h1>
</div>
</div>
<p>{config.premise}</p>
<div className="mock-header-tools">
<span className="mock-live-dot">Live</span>
<span className="mock-system">NATS 3ms / US-EAST-1</span>
<span className="mock-clock">09:41:23 ET</span>
<span className="mock-mode">{config.mode}</span>
</div>
<nav className="mock-switcher" aria-label="Mock variants">
{variantOrder.map((item, index) => (
<Link
aria-current={item === active ? "page" : undefined}
className={item === active ? "is-active" : ""}
href={`/${item}`}
key={item}
>
Mock {index + 1}
</Link>
))}
</nav>
</header>
);
}
function TickerRail() {
return (
<div className="mock-ticker-rail" aria-label="Live symbol ticker">
<div className="mock-ticker-track">
{[...tickers, ...tickers].map(([symbol, price, move, direction], index) => (
<article className="mock-ticker-card" key={`${symbol}-${index}`}>
<div>
<strong>{symbol}</strong>
<span>{price}</span>
</div>
<span className={`mock-move is-${direction}`}>{move}</span>
<Sparkline direction={direction} />
</article>
))}
</div>
</div>
);
}
function ClassicLayout() {
return (
<div className="mock-dashboard-grid mock-grid-classic">
<OptionTape />
<ChartPanel />
<SignalPanel />
<FeedHealth />
<DarkFlow />
<EventContext />
<ReplayRail compact />
</div>
);
}
function FocusLayout() {
return (
<div className="mock-dashboard-grid mock-grid-focus">
<SymbolBrief />
<ChartPanel />
<EventContext />
<OptionTape condensed />
<SignalPanel />
<DarkFlow />
</div>
);
}
function SignalLayout() {
return (
<div className="mock-dashboard-grid mock-grid-signals">
<SignalPanel hero />
<OptionTape />
<ChartPanel compact />
<FeedHealth />
<EventContext />
</div>
);
}
function ReplayLayout() {
return (
<div className="mock-dashboard-grid mock-grid-replay">
<ReplayRail />
<ChartPanel />
<EventContext />
<OptionTape condensed />
<SignalPanel />
<DarkFlow />
</div>
);
}
function Panel({
title,
meta,
className = "",
children
}: {
title: string;
meta?: string;
className?: string;
children: ReactNode;
}) {
return (
<section className={`mock-panel ${className}`} aria-label={title}>
<div className="mock-panel-head">
<h2>{title}</h2>
{meta ? <span>{meta}</span> : null}
</div>
{children}
</section>
);
}
function OptionTape({ condensed = false }: { condensed?: boolean }) {
const rows = condensed ? optionRows.slice(0, 5) : optionRows;
return (
<Panel title="Option Flow Tape" meta="250+ shown" className="mock-option-tape">
<div className="mock-table mock-table-options">
<div className="mock-table-row mock-table-head">
<span>Time</span>
<span>Symbol</span>
<span>Exp</span>
<span>Strike</span>
<span>Size</span>
<span>Prem</span>
<span>Type</span>
<span>Score</span>
</div>
{rows.map((row) => (
<div className="mock-table-row" key={`${row[0]}-${row[1]}-${row[3]}`}>
{row.map((cell, index) => (
<span
className={
index === 6
? "mock-pill is-info"
: index === 7
? `mock-pill ${cell === "Bearish" ? "is-bearish" : "is-bullish"}`
: ""
}
key={cell}
>
{cell}
</span>
))}
</div>
))}
</div>
</Panel>
);
}
function ChartPanel({ compact = false }: { compact?: boolean }) {
return (
<Panel title="AAPL | Price & Flow" meta="1m / 5m / 15m" className={compact ? "mock-chart is-compact" : "mock-chart"}>
<div className="mock-chart-meta">
<strong>194.88</strong>
<span className="mock-move is-up">+2.34 (+1.22%)</span>
</div>
<div className="mock-candle-field" aria-hidden="true">
{Array.from({ length: 58 }).map((_, index) => (
<span
className={index % 7 === 0 || index % 11 === 0 ? "is-red" : "is-green"}
key={index}
style={{ "--height": `${18 + ((index * 17) % 62)}%` } as CSSProperties}
/>
))}
</div>
<div className="mock-volume-field" aria-hidden="true">
{Array.from({ length: 42 }).map((_, index) => (
<span
className={index % 6 === 0 ? "is-red" : "is-green"}
key={index}
style={{ "--height": `${14 + ((index * 23) % 68)}%` } as CSSProperties}
/>
))}
</div>
</Panel>
);
}
function SignalPanel({ hero = false }: { hero?: boolean }) {
return (
<Panel title="Signals & Alerts" meta="All / Signals / System" className={hero ? "mock-signals is-hero" : "mock-signals"}>
<div className="mock-signal-list">
{signals.map(([time, title, symbol, value, tag]) => (
<article className="mock-signal-item" key={`${time}-${title}`}>
<time>{time}</time>
<div>
<strong>{title}</strong>
<span>{symbol} / {value}</span>
</div>
<span className={`mock-pill ${tag === "Bearish" ? "is-bearish" : tag === "News" ? "is-news" : "is-bullish"}`}>
{tag}
</span>
</article>
))}
</div>
</Panel>
);
}
function FeedHealth() {
return (
<Panel title="Feed Health" meta="Live checks" className="mock-feed">
<div className="mock-table mock-table-feed">
{feedHealth.map(([feed, status, lag, rate]) => (
<div className="mock-table-row" key={feed}>
<span>{feed}</span>
<span className={`mock-pill ${status === "Degraded" ? "is-warning" : "is-bullish"}`}>{status}</span>
<span>{lag}</span>
<span>{rate}/s</span>
</div>
))}
</div>
</Panel>
);
}
function DarkFlow() {
return (
<Panel title="Dark Flow" meta="Equity prints" className="mock-dark-flow">
<div className="mock-table mock-table-dark">
{darkFlow.map(([time, symbol, side, size, notional, type]) => (
<div className="mock-table-row" key={`${time}-${side}-${size}`}>
<span>{time}</span>
<strong>{symbol}</strong>
<span className={`mock-pill ${side === "Sell" ? "is-bearish" : "is-bullish"}`}>{side}</span>
<span>{size}</span>
<span>{notional}</span>
<span>{type}</span>
</div>
))}
</div>
</Panel>
);
}
function EventContext() {
return (
<Panel title="Event Context" meta="Window: 15m" className="mock-context">
<div className="mock-event-layout">
<ol className="mock-timeline">
{signals.slice(0, 4).map(([time, title, symbol]) => (
<li key={`${time}-${title}`}>
<time>{time}</time>
<strong>{title}</strong>
<span>{symbol} evidence linked</span>
</li>
))}
</ol>
<div className="mock-detail">
<h3>Why it fired</h3>
<dl>
<div>
<dt>Type</dt>
<dd>Dark Flow Sweep</dd>
</div>
<div>
<dt>Premium</dt>
<dd>$4.32M</dd>
</div>
<div>
<dt>Venue</dt>
<dd>Off-exchange</dd>
</div>
<div>
<dt>Tags</dt>
<dd>Bullish / Sweep / Call</dd>
</div>
</dl>
</div>
</div>
</Panel>
);
}
function ReplayRail({ compact = false }: { compact?: boolean }) {
return (
<Panel title="Replay" meta="May 16, 2024" className={compact ? "mock-replay is-compact" : "mock-replay"}>
<div className="mock-replay-controls">
<button type="button">Prev</button>
<button type="button">Pause</button>
<button type="button">Next</button>
<span>32x</span>
</div>
<div className="mock-replay-track">
<span className="mock-replay-window" />
<span className="mock-replay-now" />
</div>
<div className="mock-replay-times">
<span>09:00</span>
<strong>09:41:23 / Live</strong>
<span>10:15</span>
</div>
</Panel>
);
}
function SymbolBrief() {
return (
<Panel title="AAPL Evidence Brief" meta="Focused symbol" className="mock-symbol-brief">
<div className="mock-brief-price">
<strong>194.88</strong>
<span className="mock-move is-up">+1.22%</span>
</div>
<p>
Dark sweep pressure aligns with short-window momentum and a fresh news catalyst. Context confidence is high, but
the largest block remains off-exchange and should be checked against next print behavior.
</p>
<div className="mock-brief-tags">
<span className="mock-pill is-bullish">Bullish</span>
<span className="mock-pill is-info">Sweep</span>
<span className="mock-pill is-news">News linked</span>
</div>
</Panel>
);
}
function Sparkline({ direction }: { direction: string }) {
return (
<svg className="mock-sparkline" viewBox="0 0 96 28" role="img" aria-label={`${direction} sparkline`}>
<polyline
fill="none"
points={
direction === "down"
? "0,8 9,12 18,10 27,17 36,14 45,21 54,18 63,23 72,19 81,24 96,20"
: "0,22 9,18 18,20 27,13 36,15 45,9 54,12 63,6 72,10 81,4 96,7"
}
/>
</svg>
);
}

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@ const mono = IBM_Plex_Mono({
});
export const metadata = {
title: "Islandflow Terminal",
title: "islandflow terminal",
description: "Realtime options flow and off-exchange analysis terminal"
};

View file

@ -0,0 +1,7 @@
import { DashboardMock } from "../dashboard-mocks";
export const dynamic = "force-dynamic";
export default function Mock1Page() {
return <DashboardMock variant="mock1" />;
}

View file

@ -0,0 +1,7 @@
import { DashboardMock } from "../dashboard-mocks";
export const dynamic = "force-dynamic";
export default function Mock2Page() {
return <DashboardMock variant="mock2" />;
}

View file

@ -0,0 +1,7 @@
import { DashboardMock } from "../dashboard-mocks";
export const dynamic = "force-dynamic";
export default function Mock3Page() {
return <DashboardMock variant="mock3" />;
}

View file

@ -0,0 +1,7 @@
import { DashboardMock } from "../dashboard-mocks";
export const dynamic = "force-dynamic";
export default function Mock4Page() {
return <DashboardMock variant="mock4" />;
}

View file

@ -352,10 +352,10 @@ export const getRouteFeatures = (pathname: string): RouteFeatures => {
case "/":
default:
return {
options: false,
options: true,
nbbo: false,
equities: true,
flow: false,
flow: true,
news: true,
alerts: true,
smartMoney: true,
@ -364,17 +364,17 @@ export const getRouteFeatures = (pathname: string): RouteFeatures => {
equityJoins: true,
equityCandles: true,
equityOverlay: true,
showOptionsPane: false,
showOptionsPane: true,
showEquitiesPane: true,
showFlowPane: false,
showFlowPane: true,
showNewsPane: true,
showAlertsPane: true,
showClassifierPane: false,
showDarkPane: false,
showDarkPane: true,
showChartPane: true,
showFocusPane: false,
showReplayConsole: false,
needsClassifierDecor: false,
needsClassifierDecor: true,
needsAlertEvidencePrefetch: true,
needsDarkUnderlying: true
};
@ -4215,24 +4215,24 @@ const CandleChart = ({
width,
height,
layout: {
background: { color: "#fffdf7" },
textColor: "#4e3e25"
background: { color: "#0d141b" },
textColor: "#90a0b2"
},
grid: {
vertLines: { color: "rgba(82, 64, 36, 0.12)" },
horzLines: { color: "rgba(82, 64, 36, 0.12)" }
vertLines: { color: "rgba(144, 160, 178, 0.12)" },
horzLines: { color: "rgba(144, 160, 178, 0.12)" }
},
crosshair: {
vertLine: { color: "rgba(47, 109, 79, 0.35)" },
horzLine: { color: "rgba(47, 109, 79, 0.35)" }
vertLine: { color: "rgba(245, 166, 35, 0.32)" },
horzLine: { color: "rgba(245, 166, 35, 0.32)" }
},
timeScale: {
borderColor: "rgba(111, 91, 57, 0.35)",
borderColor: "rgba(144, 160, 178, 0.24)",
timeVisible: true,
secondsVisible: intervalMs < 60000
},
rightPriceScale: {
borderColor: "rgba(111, 91, 57, 0.35)"
borderColor: "rgba(144, 160, 178, 0.24)"
}
});
@ -4250,11 +4250,11 @@ const CandleChart = ({
overlayCtxRef.current = overlayCanvas.getContext("2d");
const series = chart.addCandlestickSeries({
upColor: "#2f6d4f",
downColor: "#c46f2a",
upColor: "#25c17a",
downColor: "#ff6b5f",
borderVisible: false,
wickUpColor: "#2f6d4f",
wickDownColor: "#c46f2a"
wickUpColor: "#25c17a",
wickDownColor: "#ff6b5f"
});
chartRef.current = chart;
@ -8397,6 +8397,278 @@ const ChartPane = memo(({ state, title = "Chart" }: ChartPaneProps) => {
);
});
type CommandDeckTicker = {
symbol: string;
price: number | null;
move: number | null;
options: number;
alerts: number;
};
const buildCommandDeckTickers = (state: TerminalState): CommandDeckTicker[] => {
const symbols = new Set<string>();
for (const symbol of state.activeTickers) {
symbols.add(symbol);
}
for (const print of state.filteredEquities.slice(0, 80)) {
symbols.add(print.underlying_id.toUpperCase());
}
for (const print of state.filteredOptions.slice(0, 80)) {
const parsed = parseOptionContractId(normalizeContractId(print.option_contract_id));
const symbol = (print.underlying_id ?? parsed?.root ?? extractUnderlying(print.option_contract_id))?.toUpperCase();
if (symbol) {
symbols.add(symbol);
}
}
for (const event of state.filteredSmartMoneyEvents.slice(0, 30)) {
symbols.add(event.underlying_id.toUpperCase());
}
for (const story of state.filteredNews.slice(0, 20)) {
for (const symbol of story.resolved_symbols) {
symbols.add(symbol.toUpperCase());
}
}
if (symbols.size === 0) {
symbols.add(state.chartTicker.toUpperCase());
}
return Array.from(symbols).slice(0, 10).map((symbol) => {
const equityPrints = state.filteredEquities
.filter((print) => print.underlying_id.toUpperCase() === symbol)
.slice(0, 2);
const price = equityPrints[0]?.price ?? null;
const previous = equityPrints[1]?.price ?? null;
const move = price !== null && previous !== null && previous !== 0 ? (price - previous) / previous : null;
const options = state.filteredOptions
.slice(0, 120)
.filter((print) => {
const parsed = parseOptionContractId(normalizeContractId(print.option_contract_id));
const underlying = (print.underlying_id ?? parsed?.root ?? extractUnderlying(print.option_contract_id))?.toUpperCase();
return underlying === symbol;
}).length;
const alerts = state.filteredAlerts
.slice(0, 80)
.filter((alert) => alert.trace_id.toUpperCase().includes(symbol)).length;
return { symbol, price, move, options, alerts };
});
};
const CommandDeckHeader = ({ state }: { state: TerminalState }) => {
const focus = state.activeTickers.length > 0 ? state.activeTickers.join(", ") : state.chartTicker;
const selected = state.selectedInstrumentLabel ?? "No contract lock";
const connectionLabel = state.mode === "live" ? statusLabel(state.liveSession.status, false, state.mode) : "Replay";
return (
<header className="command-deck-header" aria-label="Command deck context">
<div className="command-deck-brand">
<span className="command-deck-mark" aria-hidden="true" />
<div>
<span className="command-deck-kicker">islandflow</span>
<h2>Command Deck</h2>
</div>
</div>
<div className="command-deck-brief">
<span>Evidence console</span>
<strong>{focus}</strong>
<span>{selected}</span>
</div>
<div className="command-deck-controls" aria-label="Active command deck controls">
<span className={`command-chip command-chip-${state.liveSession.status}`}>
{state.mode === "live" ? "Live" : "Replay"}: {connectionLabel}
</span>
<span className="command-chip">Last {state.lastSeen ? formatTime(state.lastSeen) : "waiting"}</span>
<button className="terminal-button" type="button" onClick={state.toggleMode}>
{state.mode === "live" ? "Switch to Replay" : "Switch to Live"}
</button>
</div>
</header>
);
};
const TickerRail = ({ state }: { state: TerminalState }) => {
const tickers = useMemo(() => buildCommandDeckTickers(state), [state]);
return (
<div className="command-ticker-rail" aria-label="Live ticker focus rail">
<div className="command-ticker-track">
{tickers.map((ticker) => {
const direction = ticker.move === null ? "flat" : ticker.move >= 0 ? "up" : "down";
const equity = state.filteredEquities.find((print) => print.underlying_id.toUpperCase() === ticker.symbol);
return (
<button
className={`command-ticker-card is-${direction}`}
key={ticker.symbol}
type="button"
onClick={() => (equity ? state.focusEquityTicker(equity) : state.setFilterInput(ticker.symbol))}
>
<span className="command-ticker-symbol">{ticker.symbol}</span>
<span className="command-ticker-price">{ticker.price === null ? "--" : `$${formatPrice(ticker.price)}`}</span>
<span className="command-ticker-move">
{ticker.move === null
? "Move n/a"
: `${direction === "up" ? "Up" : "Down"} ${formatPct(Math.abs(ticker.move))}`}
</span>
<span className="command-ticker-meta">
{ticker.options} opt / {ticker.alerts} alerts
</span>
</button>
);
})}
</div>
</div>
);
};
const FeedHealthPane = ({ state }: { state: TerminalState }) => {
const rows = [
{ label: "Options", tape: state.options, subscribed: state.routeFeatures.options },
{ label: "Equities", tape: state.equities, subscribed: state.routeFeatures.equities },
{ label: "Flow", tape: state.flow, subscribed: state.routeFeatures.flow },
{ label: "Alerts", tape: state.alerts, subscribed: state.routeFeatures.alerts },
{ label: "News", tape: state.news, subscribed: state.routeFeatures.news },
{ label: "Dark", tape: state.inferredDark, subscribed: state.routeFeatures.inferredDark }
];
return (
<Pane
className="command-feed-pane"
title="Feed Health"
status={<span className="command-pane-meta">{state.liveSession.manifest.length} subscriptions</span>}
>
<div className="command-health-list">
{rows.map(({ label, tape, subscribed }) => (
<div className="command-health-row" key={label}>
<span>{label}</span>
<span className={`command-health-status command-health-${tape.status}`}>
{subscribed ? statusLabel(tape.status, tape.paused, state.mode) : "Idle"}
</span>
<span>{tape.lastUpdate ? formatTime(tape.lastUpdate) : "No update"}</span>
<span>{tape.dropped > 0 ? `${tape.dropped} dropped` : "Queue clear"}</span>
</div>
))}
</div>
</Pane>
);
};
const EventContextPane = ({ state }: { state: TerminalState }) => {
const events = [
...state.filteredAlerts.slice(0, 3).map((alert) => ({
key: `alert-${alert.trace_id}-${alert.seq}`,
ts: alert.source_ts,
label: "Alert",
title: alert.hits[0] ? humanizeClassifierId(alert.hits[0].classifier_id) : "Classifier alert",
detail: alert.hits[0]?.explanations?.[0] ?? `${alert.hits.length} linked hits`,
action: () => state.setSelectedAlert(alert)
})),
...state.filteredSmartMoneyEvents.slice(0, 3).map((event) => ({
key: `smart-${event.event_id}-${event.seq}`,
ts: event.source_ts,
label: "Smart",
title: smartMoneyProfileLabel(event.primary_profile_id),
detail: `${event.underlying_id} ${normalizeDirection(event.primary_direction)} / ${event.packet_ids.length} packets`,
action: () => state.openFromSmartMoneyEvent(event)
})),
...state.filteredInferredDark.slice(0, 3).map((event) => ({
key: `dark-${event.trace_id}-${event.seq}`,
ts: event.source_ts,
label: "Dark",
title: humanizeClassifierId(event.type),
detail: `${event.evidence_refs.length} evidence refs / confidence ${formatConfidence(event.confidence)}`,
action: () => state.setSelectedDarkEvent(event)
})),
...state.filteredNews.slice(0, 2).map((story) => ({
key: `news-${story.trace_id}-${story.seq}`,
ts: story.published_ts,
label: "News",
title: story.headline,
detail: story.resolved_symbols.length > 0 ? story.resolved_symbols.join(", ") : story.source,
action: () => state.setSelectedNewsStory(story)
}))
].sort((a, b) => b.ts - a.ts).slice(0, 6);
return (
<Pane
className="command-context-pane"
title="Event Context"
status={<span className="command-pane-meta">Focus evidence</span>}
>
{events.length === 0 ? (
<div className="empty">No linked evidence is available for this scope yet.</div>
) : (
<div className="command-context-list" role="list">
{events.map((event) => (
<button className="command-context-row" key={event.key} type="button" onClick={event.action}>
<time>{formatTime(event.ts)}</time>
<span className="command-context-kind">{event.label}</span>
<strong>{event.title}</strong>
<span>{event.detail}</span>
</button>
))}
</div>
)}
</Pane>
);
};
const HomeReplayRail = ({ state }: { state: TerminalState }) => {
const replayTime =
state.options.replayTime ??
state.equities.replayTime ??
state.flow.replayTime ??
state.alerts.replayTime ??
state.inferredDark.replayTime;
const replayComplete =
state.options.replayComplete ||
state.equities.replayComplete ||
state.flow.replayComplete ||
state.alerts.replayComplete ||
state.inferredDark.replayComplete;
const activeSource = state.replaySource ? state.replaySource.toUpperCase() : state.mode === "live" ? "LIVE HEAD" : "AUTO";
return (
<Pane
className="command-replay-pane"
title="Replay / Mode"
status={
<TapeStatus
status={state.mode === "live" ? state.liveSession.status : state.options.status}
lastUpdate={state.lastSeen}
replayTime={replayTime}
replayComplete={replayComplete}
paused={false}
dropped={state.options.dropped + state.equities.dropped + state.flow.dropped + state.alerts.dropped}
mode={state.mode}
/>
}
actions={
<button className="terminal-button" type="button" onClick={state.toggleMode}>
{state.mode === "live" ? "Replay" : "Live"}
</button>
}
>
<div className="command-replay-strip">
<div>
<span>Source</span>
<strong>{activeSource}</strong>
</div>
<div>
<span>Cursor</span>
<strong>{replayTime ? formatTime(replayTime) : state.lastSeen ? formatTime(state.lastSeen) : "waiting"}</strong>
</div>
<div>
<span>Chart</span>
<strong>{state.chartTicker} / {formatIntervalLabel(state.chartIntervalMs)}</strong>
</div>
<div>
<span>Scope</span>
<strong>{state.activeTickers.length > 0 ? state.activeTickers.join(", ") : "All symbols"}</strong>
</div>
</div>
</Pane>
);
};
const FocusPane = memo(({ state }: { state: TerminalState }) => {
const hits = state.chartSmartMoneyEvents.slice(-10).reverse();
const dark = state.chartInferredDark.slice(-10).reverse();
@ -8958,7 +9230,7 @@ export function TerminalAppShell({ children }: { children: ReactNode }) {
<div className="terminal-drawer-head">
<div className="terminal-brand">
<span className="terminal-brand-kicker">IF</span>
<span className="terminal-brand-name">Islandflow</span>
<span className="terminal-brand-name">islandflow</span>
</div>
<button
aria-label="Close navigation drawer"
@ -9040,11 +9312,18 @@ export function OverviewRoute() {
const state = useTerminal();
return (
<PageFrame title="Home">
<div className="page-grid page-grid-home">
<ChartPane state={state} />
<EquitiesPane state={state} />
<NewsPane state={state} limit={6} />
<AlertsPane state={state} withStrip />
<div className="command-deck-shell">
<CommandDeckHeader state={state} />
<TickerRail state={state} />
<div className="command-deck-grid">
<OptionsPane state={state} limit={14} />
<ChartPane state={state} title="Price / Flow" />
<AlertsPane state={state} limit={8} withStrip className="command-signals-pane" />
<FeedHealthPane state={state} />
<DarkPane state={state} limit={8} className="command-dark-pane" />
<EventContextPane state={state} />
<HomeReplayRail state={state} />
</div>
</div>
</PageFrame>
);

View file

@ -0,0 +1,387 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Standup Summary for 2026-05-24</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@500;600&family=IBM+Plex+Sans:wght@400;500;600&family=Quantico:wght@400;700&display=swap"
rel="stylesheet"
/>
<style>
:root {
color-scheme: dark;
--bg: #06080b;
--panel: rgba(17, 24, 32, 0.94);
--panel-2: rgba(13, 20, 27, 0.98);
--line: rgba(255, 255, 255, 0.09);
--text: #e6edf4;
--muted: #90a0b2;
--faint: #6e7b8c;
--amber: #f5a623;
--amber-soft: rgba(245, 166, 35, 0.14);
--blue: #4da3ff;
--blue-soft: rgba(77, 163, 255, 0.12);
--green: #25c17a;
--green-soft: rgba(37, 193, 122, 0.12);
--red: #ff6b5f;
--red-soft: rgba(255, 107, 95, 0.14);
--shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
--radius: 18px;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
background:
radial-gradient(circle at top right, rgba(245, 166, 35, 0.14), transparent 28rem),
radial-gradient(circle at top left, rgba(77, 163, 255, 0.1), transparent 24rem),
linear-gradient(180deg, #081018 0%, var(--bg) 34%, #05070a 100%);
color: var(--text);
font-family: "IBM Plex Sans", system-ui, sans-serif;
line-height: 1.6;
}
main {
width: min(1100px, calc(100% - 32px));
margin: 0 auto;
padding: 30px 0 56px;
}
.hero,
section {
border: 1px solid var(--line);
border-radius: var(--radius);
background: linear-gradient(180deg, var(--panel), var(--panel-2));
}
.hero {
padding: 30px;
box-shadow: var(--shadow);
}
section {
margin-top: 18px;
padding: 22px;
}
.eyebrow,
h2,
.chip,
.commit-id,
code,
pre {
font-family: "IBM Plex Mono", monospace;
}
.eyebrow {
display: inline-flex;
padding: 6px 10px;
border-radius: 999px;
background: var(--amber-soft);
color: var(--amber);
font-size: 0.76rem;
letter-spacing: 0.12em;
text-transform: uppercase;
}
h1,
h3 {
margin: 0;
font-family: "Quantico", sans-serif;
letter-spacing: 0.05em;
}
h1 {
margin-top: 16px;
font-size: clamp(2.2rem, 4vw, 3.5rem);
line-height: 1.03;
text-transform: uppercase;
}
h2 {
margin: 0 0 14px;
color: var(--amber);
font-size: 0.84rem;
letter-spacing: 0.12em;
text-transform: uppercase;
}
h3 {
font-size: 1rem;
}
p,
li {
max-width: 78ch;
color: var(--muted);
}
.hero p {
margin: 16px 0 0;
font-size: 1.02rem;
}
.meta,
.grid {
display: grid;
gap: 12px;
}
.meta {
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
margin-top: 22px;
}
.card,
.timeline-item,
.callout {
padding: 16px 18px;
border: 1px solid var(--line);
border-radius: 14px;
background: rgba(255, 255, 255, 0.025);
}
.label {
display: block;
margin-bottom: 6px;
color: var(--text);
font-size: 0.74rem;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.value-strong {
color: var(--text);
font-size: 1.2rem;
font-weight: 600;
}
.chip-row,
.file-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.chip,
.file-pill {
display: inline-flex;
align-items: center;
padding: 6px 10px;
border-radius: 999px;
border: 1px solid var(--line);
background: rgba(255, 255, 255, 0.03);
color: var(--text);
font-size: 0.74rem;
letter-spacing: 0.04em;
}
.good {
background: var(--green-soft);
color: var(--green);
}
.info {
background: var(--blue-soft);
color: var(--blue);
}
.risk {
background: var(--red-soft);
color: var(--red);
}
.timeline-meta {
display: flex;
flex-wrap: wrap;
gap: 10px 14px;
margin-bottom: 10px;
}
.commit-id {
color: var(--blue);
font-size: 0.76rem;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.timestamp {
color: var(--faint);
font-size: 0.76rem;
letter-spacing: 0.08em;
text-transform: uppercase;
}
ul {
margin: 0;
padding-left: 1.2rem;
}
li + li {
margin-top: 8px;
}
code {
color: #ffd596;
}
pre {
margin: 0;
padding: 14px 16px;
border-radius: 14px;
border: 1px solid var(--line);
background: rgba(4, 9, 14, 0.92);
overflow-x: auto;
color: #ffd596;
font-size: 0.86rem;
}
a {
color: #8bc1ff;
}
@media (max-width: 720px) {
main {
width: min(100% - 20px, 1100px);
padding-top: 18px;
padding-bottom: 32px;
}
.hero,
section {
padding: 18px;
}
}
</style>
</head>
<body>
<main>
<section class="hero">
<div class="eyebrow">Daily Git Summary</div>
<h1>Standup Summary for 2026-05-24</h1>
<p>
No git commits, merges, or file-level history entries were recorded on
<code>2026-05-24</code> across local branches or Forgejo-tracked refs for
this repository.
</p>
<div class="meta">
<div class="card">
<span class="label">Commits Found</span>
<span class="value-strong">0</span>
</div>
<div class="card">
<span class="label">Merged PRs Found</span>
<span class="value-strong">0</span>
</div>
<div class="card">
<span class="label">Touched Files Found</span>
<span class="value-strong">0</span>
</div>
<div class="card">
<span class="label">Scope Checked</span>
<span class="value-strong">All refs</span>
</div>
</div>
</section>
<section>
<h2>Summary</h2>
<div class="grid">
<div class="card">
<p>
The repository shows a quiet day on <code>2026-05-24</code>. Both
<code>git log</code> queries scoped to the date and
<code>git log --all</code> across local and remote refs returned no
commit entries for that window.
</p>
</div>
<div class="chip-row">
<span class="chip good">No code shipped</span>
<span class="chip info">No PR merges recorded</span>
<span class="chip risk">Git-only summary</span>
</div>
</div>
</section>
<section>
<h2>Changes Made</h2>
<ul>
<li>Checked commit history for the full day window from <code>2026-05-24 00:00</code> through <code>2026-05-24 23:59:59</code>.</li>
<li>Checked all refs, including local branches and Forgejo remotes, for commit metadata on that date.</li>
<li>Confirmed there were no commit stats or touched files to report for the standup window.</li>
</ul>
</section>
<section>
<h2>Context</h2>
<div class="timeline-item">
<div class="timeline-meta">
<span class="commit-id">1a52c2c</span>
<span class="timestamp">2026-05-23 20:41:49 -0400</span>
<span class="chip info">forgejo/main</span>
<span class="chip info">PR #12</span>
</div>
<h3>Most recent repo activity before the quiet day</h3>
<p>
The latest commit before <code>2026-05-24</code> was merge commit
<code>1a52c2c9bc8369ff051a67122a9b13420057d2c5</code>,
<code>Merge pull request 'set up forgejo ci baseline' (#12)</code>, dated
<code>2026-05-23 20:41:49 -0400</code> on <code>forgejo/main</code>.
</p>
</div>
</section>
<section>
<h2>Important Implementation Details</h2>
<ul>
<li>This summary is grounded only in git history, not issue comments, chat discussion, or local uncommitted work.</li>
<li>Uncommitted changes currently present in the working tree were not attributed to <code>2026-05-24</code> activity because they do not appear in commit history.</li>
<li>The report uses commit absence as the primary finding, which is the accurate outcome for this date range.</li>
</ul>
</section>
<section>
<h2>Expected Impact for End-Users</h2>
<p>
None from yesterdays git history. With no commits or merges on
<code>2026-05-24</code>, there is no user-facing change to call out in todays
standup from repository history alone.
</p>
</section>
<section>
<h2>Validation</h2>
<p>
Verified with date-scoped git history checks and an all-refs audit.
</p>
<pre><code>git log --since='2026-05-24 00:00' --until='2026-05-24 23:59:59'
git log --all --since='2026-05-24 00:00' --until='2026-05-24 23:59:59'
git for-each-ref --sort=-committerdate refs/heads refs/remotes
git log -1 --all --before='2026-05-25 00:00'</code></pre>
</section>
<section>
<h2>Issues, Limitations, and Mitigations</h2>
<ul>
<li>This is a git-only summary, so non-commit work such as local experiments, reviews, or issue grooming would not appear here.</li>
<li><code>bd dolt pull</code> failed in this environment because the configured remote lookup expected <code>origin/main</code> and returned <code>no branches found in remote 'origin'</code>; the summary itself was unaffected because it relies on local git metadata.</li>
</ul>
</section>
<section>
<h2>Follow-up Work</h2>
<ul>
<li>No repository changes from <code>2026-05-24</code> need follow-up based on git history.</li>
<li>If a broader standup needs non-commit activity, pair this report with PR review or issue tracker notes outside git history.</li>
</ul>
</section>
</main>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,66 @@
# Stage 01 Advisory & Dependency Intelligence Summary
## Scope and coverage
- Target: `/Users/kell/dev/islandflow`.
- Repository identity resolution: `islandflow` via basename fallback. No `owner/repo` was resolved from env, git remote, or manifests, so repo-specific GitHub Security Advisory API queries were skipped.
- Local git history: available. Repo commit search found `8464287 fix cves from forgejo issue 10 with dependency upgrades` and index commit `bff5334`, indicating recent dependency security remediation.
- First-party advisory signals: no project-owned CVE/GHSA IDs found outside installed `node_modules` and piolium artifacts.
- NVD keyword query for `islandflow`: 0 results.
- OSV batch query against npm dependencies: 116 historical advisories across dependency names. These are dependency-history signals, not all applicable to the pinned/ranged versions.
## Advisory inventory highlights
| Package/component | Advisory | Severity | CVE/alias | Affected / fixed range from OSV | Relevance to Islandflow |
|---|---:|---|---|---|---|
| `next` / web middleware | GHSA-f82v-jwr5-mffw | CRITICAL | CVE-2025-29927 | introduced 13.0.0; fixed 13.5.9 | Current `next ^16.2.6` appears beyond fixed range, but this class maps directly to auth/route middleware review. |
| `next` / script rendering | GHSA-gx5p-jg67-6x7h | MODERATE | CVE-2026-44580 | introduced 13.0.0; fixed 15.5.16 | Current range appears beyond fixed range; still informs XSS review for UI data rendering. |
| `next` / middleware redirect | GHSA-4342-x723-ch2f | MODERATE | CVE-2025-57822 | introduced 0.9.9; fixed 14.2.32 | Current range appears beyond fixed range; SSRF/redirect behavior remains important around API origin controls. |
| `next` / authorization | GHSA-7gfc-8cq8-jh5f | HIGH | CVE-2024-51479 | introduced 9.5.5; fixed 14.2.15 | Current range appears beyond fixed range; historical pattern is auth bypass in path/middleware matching. |
| `ws` | GHSA-2mhh-w6q8-5hxw | LOW | CVE-2016-10518 | introduced 0; fixed 1.0.1 | Current `ws ^8.21.0` appears beyond fixed range; websocket parsing and resource handling remain high-value. |
| `redis` | GHSA-35q2-47q7-3pc3 | HIGH | CVE-2021-29469 | introduced 2.6.0; fixed 3.1.1 | Current `redis ^5.10.0` appears beyond fixed range; Redis is security-relevant for hot caches/rolling stats. |
| `zod` | GHSA-m95q-7qp3-xv42 | MODERATE | CVE-2023-4316 | introduced 0; fixed 3.22.3 | Current `zod ^3.23.8` appears beyond fixed range; validates DoS risk from schema parsing. |
| `nats` | GHSA-prmc-5v5w-c465 | CRITICAL | none | introduced 2.0.0-201; fixed 2.0.0-209 | Current `nats ^2.24.0` appears beyond fixed range; credentials/TLS configuration remains critical. |
| `electron` | GHSA-2q4g-w47c-4674 | HIGH | CVE-2020-15174 | introduced 8.0.0-beta.0; fixed 8.5.1 | Current `electron ^39.2.0` appears beyond fixed range; desktop navigation/origin controls remain core. |
| `react-dom` | GHSA-mvjj-gqq2-p4hw | MODERATE | CVE-2018-6341 | introduced 16.0.0; fixed 16.0.1 | Current `react-dom ^19.2.0` appears beyond fixed range; historical XSS pattern relevant to rendering market/news data. |
OSV historical advisory counts by dependency name: `next` 55, `electron` 48, `ws` 6, `nats` 2, `react` 2, `react-dom` 1, `redis` 1, `zod` 1.
## Dependency intelligence
- Runtime stack: Bun workspaces, TypeScript, Next.js web frontend, Electron shell, multiple TS services, plus optional Python sidecars for IBKR/Databento options replay.
- Security-relevant direct dependencies:
- `next ^16.2.6`, `react ^19.2.0`, `react-dom ^19.2.0`: public web UI and route surface. Historical patterns: auth bypass, middleware matching, SSRF redirects, cache poisoning, XSS.
- `electron ^39.2.0`: desktop shell that loads hosted/local app. Historical patterns: navigation escape, protocol/IPC misuse, sandbox and origin boundary failures.
- `ws ^8.21.0`: live market/news ingest websocket clients. Risk: parser/resource exhaustion and trust in third-party market data.
- `nats ^2.24.0`: event bus/JetStream control plane. Risk: credential exposure, subject authorization, replay/control messages.
- `redis ^5.10.0`: hot caches and rolling metrics. Risk: cache poisoning, key construction, TTL abuse, DoS.
- `@clickhouse/client ^0.2.6`: durable event/history store. Risk: query construction, cursor pagination, large result-set DoS.
- `zod ^3.23.8`: schema validation. Risk: validation DoS and inconsistent parse/sanitize boundaries.
- `@msgpack/msgpack ^3.1.3`: binary decode in options ingest. Risk: malformed binary/resource exhaustion.
- `@pierre/diffs ^1.2.2`: low-visibility dependency; should be inspected for maintainer health and reachable use.
- Root overrides pin `postcss`, `tar`, and `tmp`, suggesting prior remediation of known transitive CVEs.
## Architecture hints
- Components: `apps/web` Next.js UI; `apps/desktop` Electron shell; services for API, options/equities/news ingest, candles, compute, replay, refdata, eod-enricher; shared packages for bus, config, observability, storage, types.
- Transports/data stores: REST, WebSocket, NATS/JetStream, ClickHouse HTTP, Redis, external Alpaca websockets/REST, Databento/IBKR Python sidecars, Docker Compose deployment.
- Trust boundaries: internet/user-facing web and API; desktop-local Electron-to-hosted-app boundary; third-party market data feeds; internal NATS subjects; ClickHouse/Redis persistence; deployment/runtime environment variables containing API keys.
- Highest-risk flows for later stages:
1. API REST/WebSocket endpoints handling cursor pagination, replay/history, raw `security=all` debug views, and live channel fanout.
2. Ingest adapters accepting external websocket/binary/sidecar data before schema normalization and NATS publication.
3. NATS subject publishing/subscription and replay service controls that can reintroduce stale or attacker-controlled events.
4. Electron shell origin allowlist, navigation controls, preload/IPC exposure, and `ISLANDFLOW_DESKTOP_START_URL` handling.
5. ClickHouse query construction for filters, cursors, symbols, and time windows.
## Pattern analysis and audit targeting
- Component heatmap from dependency history: web/Next.js is hottest (55 OSV advisories), Electron desktop second (48), websocket/event-ingest layer third (`ws`, `nats`).
- Recurring bug classes to hunt: auth bypass/middleware confusion, XSS/rendering injection, SSRF/open redirect, DoS/resource exhaustion, cache poisoning, navigation/IPC boundary bypass.
- Attack surface trends: network inputs dominate: HTTP routes, WebSocket streams, NATS messages, Redis/cache keys, ClickHouse query parameters, and external market-data payloads.
- Patch-quality signal: repeated Next.js and Electron advisory history means later review should assume framework boundary fixes are historically bypass-prone and verify application-level compensating controls.
- Recommended next-stage focus: prioritize DFD slices for API live/history/replay, ingest-to-NATS normalization, Electron shell boundary, and ClickHouse storage query paths. Mandatory review chambers should include auth bypass, XSS, SSRF/open redirect, parser/validation DoS, and message/cache poisoning.
## Artifacts produced
- `piolium/attack-surface/deps.tsv` — direct dependency inventory.
- `piolium/attack-surface/npm-dep-names.txt` — unique npm package names queried.
- `piolium/attack-surface/osv-query.json` and `osv-querybatch.json` — OSV batch request/response.
- `piolium/attack-surface/osv-findings.tsv` — flattened OSV package/advisory list.
- `piolium/attack-surface/osv-selected-details.json` — detail records for representative advisories.
- `piolium/attack-surface/nvd-islandflow.json` — NVD keyword response.

View file

@ -0,0 +1,59 @@
# Islandflow Architecture Entrypoints Inventory
## Public/Network Routes
### API service (`services/api/src/index.ts`, Bun on `API_HOST:API_PORT`, default `127.0.0.1:4000`)
- Health: `GET /health`.
- Synthetic admin (Bearer token expected): `GET /admin/synthetic/status`, `GET /admin/synthetic/control`, `PUT /admin/synthetic/control`.
- Recent/live REST: `GET /prints/options`, `/nbbo/options`, `/prints/equities`, `/prints/equities/range`, `/quotes/equities`, `/candles/equities`, `/joins/equities`, `/dark/inferred`, `/flow/packets`, `/flow/smart-money`, `/flow/classifier-hits`, `/flow/alerts`, `/news`.
- Context/lookup: `GET /flow/packets/:id`, `GET /flow/alerts/:trace_id/context`, alert-context helper paths, `GET /option-prints/by-trace`, `GET /equity-joins/by-id`, `POST /lookup/options-support`.
- History: `GET /history/options`, `/history/nbbo`, `/history/equities`, `/history/equity-quotes`, `/history/equity-joins`, `/history/flow`, `/history/smart-money`, `/history/classifier-hits`, `/history/alerts`, `/history/inferred-dark`, `/history/news`.
- Replay: `GET /replay/options`, `/replay/nbbo`, `/replay/equities`, `/replay/equity-quotes`, `/replay/equity-candles`, `/replay/equity-joins`, `/replay/inferred-dark`, `/replay/flow`, `/replay/smart-money`, `/replay/classifier-hits`, `/replay/alerts`.
- WebSockets: `GET /ws/options`, `/ws/options-nbbo`, `/ws/equities`, `/ws/equity-candles`, `/ws/equity-quotes`, `/ws/equity-joins`, `/ws/inferred-dark`, `/ws/flow`, `/ws/classifier-hits`, `/ws/smart-money`, `/ws/alerts`, `/ws/live`.
### Web app (`apps/web/app`, Next.js on port 3000)
- Pages: `/`, `/tape`, `/signals`, `/charts`, `/news`, `/options`, `/replay`, `/frontend-cooker`.
- Next API admin proxy: `GET /api/admin/synthetic/status`, `GET|PUT /api/admin/synthetic/control`.
### Desktop (`apps/desktop`)
- Loads `https://flow.deltaisland.io` by default or trusted local/prod URL from `ISLANDFLOW_DESKTOP_START_URL`.
- Allows external `http:`/`https:` links only when navigation source is trusted app origin.
## Attacker-Controlled Sources
- URL path segments: packet IDs, alert trace IDs, by-id/by-trace arrays.
- Query params: `limit`, `before_ts`, `before_seq`, `after_ts`, `after_seq`, `trace_prefix`, option/equity filters, candle intervals/ranges/cache flag, source selectors.
- Request bodies: `PUT /admin/synthetic/control`, `POST /lookup/options-support`, WS `/ws/live` messages.
- WebSocket connection count, channels, subscription messages.
- External feed payloads: Alpaca options/equities/news REST+WS, Databento replay JSONL from Python, IBKR JSONL from Python, msgpack frames.
- Environment: `NEXT_PUBLIC_API_URL`, `NEXT_PUBLIC_SYNTHETIC_ADMIN`, `SYNTHETIC_ADMIN_TOKEN`, API/NATS/ClickHouse/Redis URLs, bind IPs, provider API keys, adapter choices, Python binary paths, Electron start URL.
- Internal network inputs: NATS subjects/KV, Redis cache contents, ClickHouse rows.
- CI/deploy inputs: branches/refs/env secrets, docker compose env overrides.
## High-Value Sinks
- ClickHouse `client.query({ query })`, `exec`, `insert`: `packages/storage/src/clickhouse.ts`.
- NATS `publishJson`, `subscribeJson`, stream/KV helpers: `packages/bus/src/**`.
- Redis hot live/candle cache: `services/api/src/live.ts`, candle service.
- Browser render sinks for news `content_html`, URLs, explanations/profile JSON: `apps/web/app/**`.
- Admin state mutation: `writeSyntheticControlState`, `openSyntheticControlKv`.
- Electron `BrowserWindow.loadURL`, `shell.openExternal`.
- Child execution: `Bun.spawn` in `services/ingest-options/src/adapters/databento.ts`, `ibkr.ts`, deployment scripts.
- Logs containing provider errors, URLs, trace IDs, and potential secret-bearing env/config.
## Key Source Files for Later Phases
- API routing/auth/WS: `services/api/src/index.ts`, `services/api/src/live.ts`, `services/api/src/synthetic-control.ts`, `services/api/src/option-queries.ts`, `services/api/src/alert-context.ts`.
- Storage/query construction: `packages/storage/src/clickhouse.ts`, all `packages/storage/src/*.ts` table modules.
- Bus/subjects/control: `packages/bus/src/index.ts`, `jetstream.ts`, `streams.ts`, `subjects.ts`, `synthetic-control.ts`.
- External ingestion: `services/ingest-options/src/adapters/alpaca.ts`, `databento.ts`, `ibkr.ts`, `synthetic.ts`, `services/ingest-equities/src/adapters/alpaca.ts`, `services/ingest-news/src/index.ts`.
- Compute integrity: `services/compute/src/*.ts`, `services/candles/src/*.ts`, `services/replay/src/index.ts`.
- Web/admin/UI rendering: `apps/web/app/api/admin/synthetic/shared.ts`, `control/route.ts`, `status/route.ts`, `apps/web/app/**/*.tsx`, `apps/web/next.config.mjs`.
- Desktop boundary: `apps/desktop/src/security.ts`, `apps/desktop/src/main.ts`.
- Config/secrets/env: `packages/config/src/env.ts`, `packages/config/src/alpaca.ts`, `deployment/docker/.env.example`, `deployment/docker/docker-compose.yml`.
- Deployment/CI: `scripts/deploy.ts`, `deploy`, `.forgejo/workflows/ci.yml`, `.github/workflows/*.yml`, Dockerfiles.
## Initial Custom Extraction Targets
- Remote HTTP input to ClickHouse query template literals.
- Remote WS input to JSON/zod parsing and send/broadcast loops.
- External provider/child stdout input to NATS publish and UI render fields.
- Env vars to SSRF-like fetch destinations and Electron navigation.
- Env vars to `Bun.spawn` executable/arguments.
- NATS messages to ClickHouse insert and derived compute decisions.

View file

@ -0,0 +1,153 @@
# Candidate Scan
Generated by piolium at 2026-05-27T05:18:10.316Z
## Totals
- Files scanned: 189
- Candidate files: 45
- Candidate matches: 289
- Per-file records: disabled (set PIOLIUM_FILE_RECORDS=1 to enable)
## Candidate Classes
- secret-literal: 2 match(es), max score 114. Hardcoded secret-like literal.
- dynamic-code-execution: 20 match(es), max score 90. Dynamic code execution, expression evaluation, or runtime compilation.
- command-execution: 34 match(es), max score 80. Potential command execution or shell invocation with variable input.
- hidden-control-channel: 40 match(es), max score 71. Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.
- ssrf-capable-request: 25 match(es), max score 71. Outbound HTTP request site that may be attacker-controlled.
- open-redirect: 4 match(es), max score 65. Redirect sink that may accept user-controlled URLs.
- unsafe-html-or-template: 4 match(es), max score 63. HTML injection sink or template escape bypass.
- path-traversal-file-access: 99 match(es), max score 55. Filesystem access using path joins or user-controllable paths.
- raw-sql-query: 21 match(es), max score 55. Raw SQL construction or query execution that may need parameterization review.
- public-entrypoint: 40 match(es), max score 54. Public route, handler, controller, workflow, or operation entry point.
## Top Files
- `packages/storage/src/clickhouse.ts`: score 4755, 69 match(es)
- `apps/web/app/terminal.tsx`: score 2040, 38 match(es)
- `scripts/deploy.ts`: score 1795, 29 match(es)
- `services/api/src/index.ts`: score 949, 23 match(es)
- `scripts/dev.ts`: score 905, 16 match(es)
- `scripts/check-docker-workspace.ts`: score 605, 11 match(es)
- `scripts/dev-desktop.ts`: score 520, 9 match(es)
- `scripts/dev-services.ts`: score 355, 6 match(es)
- `services/api/src/live.ts`: score 316, 7 match(es)
- `scripts/check-public-api-routes.ts`: score 305, 5 match(es)
- `packages/bus/src/jetstream.ts`: score 275, 5 match(es)
- `services/compute/src/structure-packets.ts`: score 275, 5 match(es)
- `services/ingest-options/src/adapters/ibkr.ts`: score 245, 4 match(es)
- `services/api/src/option-queries.ts`: score 228, 6 match(es)
- `services/compute/src/index.ts`: score 225, 3 match(es)
- `apps/desktop/src/security.ts`: score 220, 4 match(es)
- `scripts/sync-docker-workspace.ts`: score 220, 4 match(es)
- `apps/web/app/api/admin/synthetic/shared.ts`: score 188, 3 match(es)
- `services/candles/src/index.ts`: score 170, 2 match(es)
- `services/compute/src/rolling-stats.ts`: score 170, 2 match(es)
- `services/ingest-news/src/symbols.ts`: score 170, 2 match(es)
- `apps/web/app/api/admin/synthetic/routes.test.ts`: score 168, 2 match(es)
- `apps/desktop/src/security.test.ts`: score 110, 2 match(es)
- `packages/config/src/env.ts`: score 110, 2 match(es)
- `packages/types/src/live.ts`: score 110, 2 match(es)
- `packages/types/src/options-flow.ts`: score 110, 2 match(es)
- `services/compute/src/contracts.ts`: score 110, 2 match(es)
- `services/ingest-equities/src/adapters/alpaca.ts`: score 110, 2 match(es)
- `services/ingest-options/py/databento_replay.py`: score 110, 2 match(es)
- `services/ingest-options/py/ibkr_stream.py`: score 110, 2 match(es)
- `services/replay/src/index.ts`: score 110, 2 match(es)
- `apps/web/app/terminal.test.ts`: score 90, 3 match(es)
- `packages/config/tests/alpaca.test.ts`: score 90, 1 match(es)
- `apps/web/scripts/dev.ts`: score 80, 1 match(es)
- `services/ingest-options/src/adapters/databento.ts`: score 80, 1 match(es)
- `apps/web/app/charts/page.tsx`: score 65, 1 match(es)
- `apps/web/app/replay/page.tsx`: score 65, 1 match(es)
- `apps/web/app/signals/page.tsx`: score 65, 1 match(es)
- `apps/web/app/tape/page.tsx`: score 65, 1 match(es)
- `apps/web/app/frontend-cooker/page.tsx`: score 55, 1 match(es)
## Highest-Ranked Matches
- secret-literal (precise, score 114) at `apps/web/app/api/admin/synthetic/routes.test.ts:28` - token: "secret-token"
- secret-literal (precise, score 90) at `packages/config/tests/alpaca.test.ts:60` - secret: "short-secret",
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:118` - exec(params: { query: string }): Promise<void>;
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:189` - async exec({ query }) {
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:243` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:247` - await client.exec({ query });
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:254` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:262` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:270` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:278` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:286` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:294` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:302` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:310` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:318` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:324` - await client.exec({
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:328` - await client.exec({ query });
- dynamic-code-execution (precise, score 90) at `packages/storage/src/clickhouse.ts:333` - await client.exec({
- dynamic-code-execution (precise, score 90) at `services/candles/src/index.ts:156` - await multi.exec();
- dynamic-code-execution (precise, score 90) at `services/compute/src/index.ts:351` - const match = SYNTHETIC_EVENT_CONDITION_RE.exec(condition);
- dynamic-code-execution (precise, score 90) at `services/compute/src/rolling-stats.ts:163` - await multi.exec();
- dynamic-code-execution (precise, score 90) at `services/ingest-news/src/symbols.ts:27` - while ((match = regex.exec(value)) !== null) {
- command-execution (precise, score 80) at `apps/web/scripts/dev.ts:16` - const child = Bun.spawn(["next", "dev", "-p", String(port)], {
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:118` - exec(params: { query: string }): Promise<void>;
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:189` - async exec({ query }) {
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:243` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:247` - await client.exec({ query });
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:254` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:262` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:270` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:278` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:286` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:294` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:302` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:310` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:318` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:324` - await client.exec({
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:328` - await client.exec({ query });
- command-execution (precise, score 80) at `packages/storage/src/clickhouse.ts:333` - await client.exec({
- command-execution (precise, score 80) at `scripts/deploy.ts:180` - const result = spawnSync(command, args, {
- command-execution (precise, score 80) at `scripts/deploy.ts:196` - const result = spawnSync(command, args, {
- command-execution (precise, score 80) at `scripts/deploy.ts:216` - const result = spawnSync(command, args, {
- command-execution (precise, score 80) at `scripts/deploy.ts:238` - const result = spawnSync("bash", localArgs, {
- command-execution (precise, score 80) at `scripts/deploy.ts:253` - const result = spawnSync("ssh", sshArgs, {
- command-execution (precise, score 80) at `scripts/deploy.ts:402` - return spawnSync("git", ["remote", "get-url", name], {
- command-execution (precise, score 80) at `scripts/deploy.ts:581` - const result = spawnSync("bun", ["run", "check:docker-workspace"], {
- command-execution (precise, score 80) at `scripts/deploy.ts:670` - const upstreamResult = spawnSync(
- command-execution (precise, score 80) at `scripts/dev-desktop.ts:137` - const proc = Bun.spawn(cmd, {
- command-execution (precise, score 80) at `scripts/dev-services.ts:136` - const proc = Bun.spawn(cmd, {
- command-execution (precise, score 80) at `scripts/dev.ts:189` - const proc = Bun.spawn(cmd, {
- command-execution (precise, score 80) at `services/candles/src/index.ts:156` - await multi.exec();
- command-execution (precise, score 80) at `services/compute/src/index.ts:351` - const match = SYNTHETIC_EVENT_CONDITION_RE.exec(condition);
- command-execution (precise, score 80) at `services/compute/src/rolling-stats.ts:163` - await multi.exec();
- command-execution (precise, score 80) at `services/ingest-news/src/symbols.ts:27` - while ((match = regex.exec(value)) !== null) {
- command-execution (precise, score 80) at `services/ingest-options/src/adapters/databento.ts:305` - const child = Bun.spawn(buildArgs(trimmed), {
- command-execution (precise, score 80) at `services/ingest-options/src/adapters/ibkr.ts:92` - const child = Bun.spawn(args, {
- ssrf-capable-request (normal, score 71) at `apps/web/app/api/admin/synthetic/shared.ts:51` - const response = await fetch(url.toString(), {
- hidden-control-channel (normal, score 71) at `apps/web/app/api/admin/synthetic/shared.ts:60` - "content-type": response.headers.get("content-type") ?? "application/json"
- hidden-control-channel (normal, score 71) at `scripts/check-public-api-routes.ts:20` - return (response.headers.get("content-type") ?? "").toLowerCase().includes("application/json");
- ssrf-capable-request (normal, score 71) at `scripts/check-public-api-routes.ts:25` - const response = await fetch(url);
- hidden-control-channel (normal, score 71) at `scripts/check-public-api-routes.ts:34` - throw new Error(`${url.pathname} returned non-JSON content (${response.headers.get("content-type") ?? "none"}): ${sample}`);
- open-redirect (normal, score 65) at `apps/web/app/charts/page.tsx:6` - redirect("/");
- open-redirect (normal, score 65) at `apps/web/app/replay/page.tsx:6` - redirect("/");
- open-redirect (normal, score 65) at `apps/web/app/signals/page.tsx:6` - redirect("/");
- open-redirect (normal, score 65) at `apps/web/app/tape/page.tsx:6` - redirect("/options");
- hidden-control-channel (normal, score 63) at `services/api/src/index.ts:328` - const authorization = req.headers.get("authorization") ?? "";
- hidden-control-channel (normal, score 63) at `services/api/src/index.ts:332` - return req.headers.get("x-synthetic-admin-token")?.trim() ?? "";
- hidden-control-channel (normal, score 63) at `services/api/src/index.ts:2052` - logger.info("api listening", { host: env.API_HOST, port: server.port });
- unsafe-html-or-template (normal, score 63) at `services/api/src/live.ts:142` - console.warn(`Invalid ${key}="${raw}", using ${fallback}`);
- unsafe-html-or-template (normal, score 63) at `services/api/src/live.ts:161` - console.warn(`Invalid LIVE_LIMIT_DEFAULT="${raw}", using ${fallback}`);
- hidden-control-channel (normal, score 55) at `apps/desktop/src/security.test.ts:11` - it("allows the hosted production origin on /options", () => {
- hidden-control-channel (normal, score 55) at `apps/desktop/src/security.test.ts:15` - it("keeps /tape trusted as a compatibility path on the same origin", () => {
- hidden-control-channel (normal, score 55) at `apps/desktop/src/security.ts:5` - new URL(DESKTOP_PRODUCTION_URL).origin,
- hidden-control-channel (normal, score 55) at `apps/desktop/src/security.ts:6` - new URL(DESKTOP_LOCAL_DEV_URL).origin,
- hidden-control-channel (normal, score 55) at `apps/desktop/src/security.ts:26` - return TRUSTED_ORIGINS.has(url.origin);
- hidden-control-channel (normal, score 55) at `apps/desktop/src/security.ts:35` - return !TRUSTED_ORIGINS.has(url.origin);
- path-traversal-file-access (normal, score 55) at `apps/web/app/frontend-cooker/page.tsx:43` - <section className={styles.tableWrap}><table><thead><tr>{["Ticker", "Contract", "Expiry", "Notional", "Side", "Delta", "Condition"].map(h => <th key={h}>{h}</th>)}</tr></thead><tbody>{flowRows.map((r) => <tr key={r.join(
- hidden-control-channel (normal, score 55) at `apps/web/app/terminal.tsx:516` - const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
- hidden-control-channel (normal, score 55) at `apps/web/app/terminal.tsx:1024` - const host = isLocal ? `${hostname}:4000` : window.location.host;
- hidden-control-channel (normal, score 55) at `apps/web/app/terminal.tsx:1024` - const host = isLocal ? `${hostname}:4000` : window.location.host;
## Custom Matchers
Project matchers can be added at `piolium/matchers.json`, `piolium/custom-matchers.json`, or `.piolium-matchers.json`.

View file

@ -0,0 +1,289 @@
{"slug":"secret-literal","description":"Hardcoded secret-like literal.","noise":"precise","filePath":"apps/web/app/api/admin/synthetic/routes.test.ts","line":28,"snippet":"token: \"secret-token\"","matchedPattern":"secret assignment","score":114,"source":"builtin"}
{"slug":"secret-literal","description":"Hardcoded secret-like literal.","noise":"precise","filePath":"packages/config/tests/alpaca.test.ts","line":60,"snippet":"secret: \"short-secret\",","matchedPattern":"secret assignment","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":118,"snippet":"exec(params: { query: string }): Promise<void>;","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":189,"snippet":"async exec({ query }) {","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":243,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":247,"snippet":"await client.exec({ query });","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":254,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":262,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":270,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":278,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":286,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":294,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":302,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":310,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":318,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":324,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":328,"snippet":"await client.exec({ query });","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":333,"snippet":"await client.exec({","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"services/candles/src/index.ts","line":156,"snippet":"await multi.exec();","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"services/compute/src/index.ts","line":351,"snippet":"const match = SYNTHETIC_EVENT_CONDITION_RE.exec(condition);","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"services/compute/src/rolling-stats.ts","line":163,"snippet":"await multi.exec();","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"dynamic-code-execution","description":"Dynamic code execution, expression evaluation, or runtime compilation.","noise":"precise","filePath":"services/ingest-news/src/symbols.ts","line":27,"snippet":"while ((match = regex.exec(value)) !== null) {","matchedPattern":"python eval","score":90,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"apps/web/scripts/dev.ts","line":16,"snippet":"const child = Bun.spawn([\"next\", \"dev\", \"-p\", String(port)], {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":118,"snippet":"exec(params: { query: string }): Promise<void>;","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":189,"snippet":"async exec({ query }) {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":243,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":247,"snippet":"await client.exec({ query });","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":254,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":262,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":270,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":278,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":286,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":294,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":302,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":310,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":318,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":324,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":328,"snippet":"await client.exec({ query });","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"packages/storage/src/clickhouse.ts","line":333,"snippet":"await client.exec({","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/deploy.ts","line":180,"snippet":"const result = spawnSync(command, args, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/deploy.ts","line":196,"snippet":"const result = spawnSync(command, args, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/deploy.ts","line":216,"snippet":"const result = spawnSync(command, args, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/deploy.ts","line":238,"snippet":"const result = spawnSync(\"bash\", localArgs, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/deploy.ts","line":253,"snippet":"const result = spawnSync(\"ssh\", sshArgs, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/deploy.ts","line":402,"snippet":"return spawnSync(\"git\", [\"remote\", \"get-url\", name], {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/deploy.ts","line":581,"snippet":"const result = spawnSync(\"bun\", [\"run\", \"check:docker-workspace\"], {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/deploy.ts","line":670,"snippet":"const upstreamResult = spawnSync(","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/dev-desktop.ts","line":137,"snippet":"const proc = Bun.spawn(cmd, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/dev-services.ts","line":136,"snippet":"const proc = Bun.spawn(cmd, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"scripts/dev.ts","line":189,"snippet":"const proc = Bun.spawn(cmd, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"services/candles/src/index.ts","line":156,"snippet":"await multi.exec();","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"services/compute/src/index.ts","line":351,"snippet":"const match = SYNTHETIC_EVENT_CONDITION_RE.exec(condition);","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"services/compute/src/rolling-stats.ts","line":163,"snippet":"await multi.exec();","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"services/ingest-news/src/symbols.ts","line":27,"snippet":"while ((match = regex.exec(value)) !== null) {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"services/ingest-options/src/adapters/databento.ts","line":305,"snippet":"const child = Bun.spawn(buildArgs(trimmed), {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"command-execution","description":"Potential command execution or shell invocation with variable input.","noise":"precise","filePath":"services/ingest-options/src/adapters/ibkr.ts","line":92,"snippet":"const child = Bun.spawn(args, {","matchedPattern":"node child_process","score":80,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/api/admin/synthetic/shared.ts","line":51,"snippet":"const response = await fetch(url.toString(), {","matchedPattern":"fetch/http client","score":71,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/api/admin/synthetic/shared.ts","line":60,"snippet":"\"content-type\": response.headers.get(\"content-type\") ?? \"application/json\"","matchedPattern":"request header read","score":71,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/check-public-api-routes.ts","line":20,"snippet":"return (response.headers.get(\"content-type\") ?? \"\").toLowerCase().includes(\"application/json\");","matchedPattern":"request header read","score":71,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"scripts/check-public-api-routes.ts","line":25,"snippet":"const response = await fetch(url);","matchedPattern":"fetch/http client","score":71,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/check-public-api-routes.ts","line":34,"snippet":"throw new Error(`${url.pathname} returned non-JSON content (${response.headers.get(\"content-type\") ?? \"none\"}): ${sample}`);","matchedPattern":"request header read","score":71,"source":"builtin"}
{"slug":"open-redirect","description":"Redirect sink that may accept user-controlled URLs.","noise":"normal","filePath":"apps/web/app/charts/page.tsx","line":6,"snippet":"redirect(\"/\");","matchedPattern":"redirect call","score":65,"source":"builtin"}
{"slug":"open-redirect","description":"Redirect sink that may accept user-controlled URLs.","noise":"normal","filePath":"apps/web/app/replay/page.tsx","line":6,"snippet":"redirect(\"/\");","matchedPattern":"redirect call","score":65,"source":"builtin"}
{"slug":"open-redirect","description":"Redirect sink that may accept user-controlled URLs.","noise":"normal","filePath":"apps/web/app/signals/page.tsx","line":6,"snippet":"redirect(\"/\");","matchedPattern":"redirect call","score":65,"source":"builtin"}
{"slug":"open-redirect","description":"Redirect sink that may accept user-controlled URLs.","noise":"normal","filePath":"apps/web/app/tape/page.tsx","line":6,"snippet":"redirect(\"/options\");","matchedPattern":"redirect call","score":65,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/api/src/index.ts","line":328,"snippet":"const authorization = req.headers.get(\"authorization\") ?? \"\";","matchedPattern":"request header read","score":63,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/api/src/index.ts","line":332,"snippet":"return req.headers.get(\"x-synthetic-admin-token\")?.trim() ?? \"\";","matchedPattern":"request header read","score":63,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/api/src/index.ts","line":2052,"snippet":"logger.info(\"api listening\", { host: env.API_HOST, port: server.port });","matchedPattern":"proxy or original request header","score":63,"source":"builtin"}
{"slug":"unsafe-html-or-template","description":"HTML injection sink or template escape bypass.","noise":"normal","filePath":"services/api/src/live.ts","line":142,"snippet":"console.warn(`Invalid ${key}=\"${raw}\", using ${fallback}`);","matchedPattern":"template unescaped","score":63,"source":"builtin"}
{"slug":"unsafe-html-or-template","description":"HTML injection sink or template escape bypass.","noise":"normal","filePath":"services/api/src/live.ts","line":161,"snippet":"console.warn(`Invalid LIVE_LIMIT_DEFAULT=\"${raw}\", using ${fallback}`);","matchedPattern":"template unescaped","score":63,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/desktop/src/security.test.ts","line":11,"snippet":"it(\"allows the hosted production origin on /options\", () => {","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/desktop/src/security.test.ts","line":15,"snippet":"it(\"keeps /tape trusted as a compatibility path on the same origin\", () => {","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/desktop/src/security.ts","line":5,"snippet":"new URL(DESKTOP_PRODUCTION_URL).origin,","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/desktop/src/security.ts","line":6,"snippet":"new URL(DESKTOP_LOCAL_DEV_URL).origin,","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/desktop/src/security.ts","line":26,"snippet":"return TRUSTED_ORIGINS.has(url.origin);","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/desktop/src/security.ts","line":35,"snippet":"return !TRUSTED_ORIGINS.has(url.origin);","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/frontend-cooker/page.tsx","line":43,"snippet":"<section className={styles.tableWrap}><table><thead><tr>{[\"Ticker\", \"Contract\", \"Expiry\", \"Notional\", \"Side\", \"Delta\", \"Condition\"].map(h => <th key={h}>{h}</th>)}</tr></thead><tbody>{flowRows.map((r) => <tr key={r.join(","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":516,"snippet":"const contentType = response.headers.get(\"content-type\")?.toLowerCase() ?? \"\";","matchedPattern":"request header read","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":1024,"snippet":"const host = isLocal ? `${hostname}:4000` : window.location.host;","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":1024,"snippet":"const host = isLocal ? `${hostname}:4000` : window.location.host;","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":1026,"snippet":"return `${wsProtocol}://${host}${path}`;","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":1045,"snippet":"const host = isLocal ? `${hostname}:4000` : window.location.host;","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":1045,"snippet":"const host = isLocal ? `${hostname}:4000` : window.location.host;","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":1047,"snippet":"return `${httpProtocol}://${host}${path}`;","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":1301,"snippet":".join(\" \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":1424,"snippet":"const remainder = parts.slice(2).join(\" -> \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":2300,"snippet":"const response = await fetch(url.toString());","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":2450,"snippet":"const response = await fetch(url.toString());","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":3018,"snippet":"params.set(\"side\", filters.nbboSides.join(\",\"));","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":3021,"snippet":"params.set(\"type\", filters.optionTypes.join(\",\"));","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":3033,"snippet":"params.set(\"underlying_ids\", optionScope.underlying_ids.join(\",\"));","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":3123,"snippet":"params.set(\"underlying_ids\", subscription.underlying_ids.join(\",\"));","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":3755,"snippet":"const response = await fetch(url.toString());","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":4381,"snippet":"const response = await fetch(url.toString());","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":4455,"snippet":"const response = await fetch(url.toString(), { signal: abort.signal });","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":4959,"snippet":"<p className=\"drawer-empty\">Missing refs: {missingRefs.slice(0, 4).join(\", \")}</p>","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"unsafe-html-or-template","description":"HTML injection sink or template escape bypass.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":5009,"snippet":"<div className=\"drawer-note news-drawer-body\" dangerouslySetInnerHTML={{ __html: body.html }} />","matchedPattern":"dangerous html","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":5191,"snippet":"<p className=\"drawer-empty\">Suppressed: {event.suppressed_reasons.join(\", \")}</p>","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":5934,"snippet":"void fetch(buildApiUrl(buildAlertContextPath(selectedAlert.trace_id)), { signal: abort.signal })","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":6000,"snippet":"void fetch(url.toString())","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":6222,"snippet":"void fetch(buildApiUrl(\"/lookup/options-support\"), {","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":6234,"snippet":"const contentType = response.headers.get(\"content-type\")?.toLowerCase() ?? \"\";","matchedPattern":"request header read","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":6318,"snippet":"void fetch(buildApiUrl(`/flow/packets/${encodeURIComponent(selectedClassifierPacketId)}`))","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":6398,"snippet":"const response = await fetch(buildApiUrl(`/flow/packets/${encodeURIComponent(packetId)}`));","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":6432,"snippet":"void fetch(url.toString())","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":6747,"snippet":"const response = await fetch(buildApiUrl(`/flow/packets/${encodeURIComponent(packetId)}`));","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":6785,"snippet":"void fetch(url.toString())","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":7440,"snippet":"const classes = [\"terminal-pane\", className].filter(Boolean).join(\" \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":7457,"snippet":"const focus = state.activeTickers.length > 0 ? state.activeTickers.join(\", \") : \"ALL\";","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":7902,"snippet":"].filter(Boolean).join(\" | \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":8522,"snippet":"const response = await fetch(SYNTHETIC_ADMIN_PROXY_PATHS.status, {","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":8579,"snippet":"void fetch(SYNTHETIC_ADMIN_PROXY_PATHS.control, {","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"apps/web/app/terminal.tsx","line":8799,"snippet":"? derived.focus_symbols.join(\", \")","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/bus/src/jetstream.ts","line":382,"snippet":"return value.join(\",\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/bus/src/jetstream.ts","line":391,"snippet":".join(\"; \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/bus/src/jetstream.ts","line":434,"snippet":"const fields = report.retentionDrift.map((delta) => delta.field).join(\",\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/bus/src/jetstream.ts","line":458,"snippet":".join(\" \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/bus/src/jetstream.ts","line":464,"snippet":".join(\" \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/config/src/env.ts","line":16,"snippet":"const path = issue.path.length > 0 ? issue.path.join(\".\") : \"<root>\";","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/config/src/env.ts","line":19,"snippet":".join(\"; \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":120,"snippet":"query(params: { query: string; format: ClickHouseQueryFormat }): Promise<ClickHouseQueryResult>;","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":158,"snippet":"const response = await fetch(url, {","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":194,"snippet":"const rows = values.map((value) => JSON.stringify(value)).join(\"\\n\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":199,"snippet":"async query({ query, format }) {","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":214,"snippet":"const response = await fetch(url, {","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":683,"snippet":"return values.map((value) => quoteString(value)).join(\", \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1084,"snippet":"const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(\" AND \")}` : \"\";","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1085,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1102,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1118,"snippet":"const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(\" AND \")}` : \"\";","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1119,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1133,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1151,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1165,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1183,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1201,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1219,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1237,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1254,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1299,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1347,"snippet":"const alertResult = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1373,"snippet":".query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1384,"snippet":": Promise.resolve([]),","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1387,"snippet":": Promise.resolve([])","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1422,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1423,"snippet":"query: `SELECT * FROM ${OPTION_PRINTS_TABLE} WHERE ${conditions.join(\" AND \")} ORDER BY ts ASC, seq ASC LIMIT ${safeLimit}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1444,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1469,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1470,"snippet":"query: `SELECT * FROM ${EQUITY_PRINTS_TABLE} WHERE ${conditions.join(\" AND \")} ORDER BY ts ASC, seq ASC LIMIT ${safeLimit}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1492,"snippet":"const result = await client.query({","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1740,"snippet":"query: `SELECT * FROM ${OPTION_PRINTS_TABLE} WHERE ${conditions.join(\" AND \")} ORDER BY ts DESC, seq DESC LIMIT ${safeLimit}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1763,"snippet":"query: `SELECT * FROM ${OPTION_NBBO_TABLE} WHERE ${conditions.join(\" AND \")} ORDER BY ts DESC, seq DESC LIMIT ${safeLimit}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1784,"snippet":"query: `SELECT * FROM ${EQUITY_PRINTS_TABLE} WHERE ${conditions.join(\" AND \")} ORDER BY ts DESC, seq DESC LIMIT ${safeLimit}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":1987,"snippet":"query: `SELECT * FROM ${FLOW_PACKETS_TABLE} WHERE ${memberPredicates.join(\" OR \")} ORDER BY source_ts DESC, seq DESC LIMIT ${clampLookupLimit(ids.length * 4)}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":2009,"snippet":"query: `SELECT * FROM ${SMART_MONEY_EVENTS_TABLE} WHERE ${packetPredicates.join(\" OR \")} ORDER BY source_ts DESC, seq DESC LIMIT ${clampLookupLimit(ids.length * 4)}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":2031,"snippet":"query: `SELECT * FROM ${CLASSIFIER_HITS_TABLE} WHERE ${tracePredicates.join(\" OR \")} ORDER BY source_ts DESC, seq DESC LIMIT ${clampLookupLimit(ids.length * 4)}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/storage/src/clickhouse.ts","line":2128,"snippet":"query: `SELECT * FROM ${EQUITY_PRINT_JOINS_TABLE} WHERE ${whereParts.join(\" OR \")} ORDER BY source_ts DESC, seq DESC LIMIT ${lookupLimit}`,","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/types/src/live.ts","line":228,"snippet":"? `|underlyings:${[...subscription.underlying_ids].sort().join(\",\")}`","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/types/src/live.ts","line":239,"snippet":"? `|underlyings:${[...subscription.underlying_ids].sort().join(\",\")}`","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/types/src/options-flow.ts","line":88,"snippet":"const expiry = expiryParts.join(\"-\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"packages/types/src/options-flow.ts","line":89,"snippet":"const root = parts.slice(0, -5).join(\"-\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":25,"snippet":"const repoRoot = path.resolve(import.meta.dir, \"..\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":26,"snippet":"const deploymentRoot = path.join(repoRoot, \"deployment/docker/workspace-root\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":28,"snippet":"const rootPackagePath = path.join(repoRoot, \"package.json\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":29,"snippet":"const deploymentPackagePath = path.join(deploymentRoot, \"package.json\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":30,"snippet":"const rootTsconfigPath = path.join(repoRoot, \"tsconfig.base.json\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":31,"snippet":"const deploymentTsconfigPath = path.join(deploymentRoot, \"tsconfig.base.json\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":32,"snippet":"const rootLockPath = path.join(repoRoot, \"bun.lock\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":33,"snippet":"const deploymentLockPath = path.join(deploymentRoot, \"bun.lock\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":36,"snippet":"return readFile(filePath, \"utf8\");","matchedPattern":"file read/write","score":55,"source":"builtin"}
{"slug":"unsafe-html-or-template","description":"HTML injection sink or template escape bypass.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":42,"snippet":"const parsed = Function(`\"use strict\"; return (${raw});`)() as T;","matchedPattern":"template unescaped","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/check-docker-workspace.ts","line":159,"snippet":"const packageJsonPath = path.join(repoRoot, workspacePath, \"package.json\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":31,"snippet":"path.join(process.env.HOME ?? \"\", \".ssh\", \"delta_ed25519\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":89,"snippet":"const repoRoot = path.resolve(path.dirname(scriptPath), \"..\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/deploy.ts","line":104,"snippet":"native Experimental host-native Bun services managed by systemd.","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/deploy.ts","line":125,"snippet":"DEPLOY_PUBLIC_API_HEALTH_URL Optional separate public API health URL for two-origin deployments.","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":171,"snippet":".join(\" \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/deploy.ts","line":438,"snippet":"candidates.push(\"forgejo\", \"origin\", \"github\", ...localGitRemotes());","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":448,"snippet":"`Unable to resolve a deploy git remote. Checked candidates: ${deduped.join(\", \")}`","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":691,"snippet":".join(\"|\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":751,"snippet":"const units = nativeUnitsForScope(scope).map((value) => shellEscape(value)).join(\" \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":824,"snippet":": `docker compose build ${buildServices.join(\" \")}`;","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":825,"snippet":"const upCommand = `docker compose ${[...upArgs, ...rolloutServices].join(\" \")}`;","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":847,"snippet":"const units = nativeUnitsForScope(scope).map((value) => shellEscape(value)).join(\" \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":857,"snippet":"buildSteps.push(`${NATIVE_SYSTEMCTL_PREFIX} restart ${nativeUnitsForScope(scope).map((value) => shellEscape(value)).join(\" \")}`);","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":871,"snippet":"${buildSteps.join(\"\\n\")}","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":903,"snippet":"? `docker compose ps ${psServices.join(\" \")}`","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":907,"snippet":": `docker compose logs --tail=100 ${logServices.join(\" \")}`;","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"scripts/deploy.ts","line":912,"snippet":"`docker compose exec -T api bun -e 'const r = await fetch(\"http://127.0.0.1:4000/health\"); if (!r.ok) throw new Error(\"api healthcheck failed: \" + r.status); console.log(await r.text())'`","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"scripts/deploy.ts","line":918,"snippet":"`docker compose exec -T web bun -e 'const r = await fetch(\"http://127.0.0.1:3000/\"); if (!r.ok) throw new Error(\"web healthcheck failed: \" + r.status); console.log(r.status)'`","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":930,"snippet":"${checks.join(\"\\n\")}","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":936,"snippet":"const units = nativeUnitsForScope(scope).map((value) => shellEscape(value)).join(\" \");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/deploy.ts","line":967,"snippet":"${checks.join(\"\\n\")}","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-desktop.ts","line":25,"snippet":"const stateDir = path.join(process.cwd(), \".tmp\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-desktop.ts","line":26,"snippet":"const pidFile = path.join(stateDir, \"dev-desktop-runner-pids.json\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-desktop.ts","line":102,"snippet":"await writeFile(pidFile, JSON.stringify(payload, null, 2));","matchedPattern":"file read/write","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-desktop.ts","line":111,"snippet":"const raw = await readFile(pidFile, \"utf8\");","matchedPattern":"file read/write","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-desktop.ts","line":122,"snippet":".join(\", \")}`","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev-desktop.ts","line":220,"snippet":"const checkTcp = (host: string, port: number, timeoutMs = 1000): Promise<boolean> => {","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev-desktop.ts","line":222,"snippet":"const socket = net.connect({ host, port });","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-desktop.ts","line":226,"snippet":"resolve(ok);","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-services.ts","line":19,"snippet":"const stateDir = path.join(process.cwd(), \".tmp\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-services.ts","line":20,"snippet":"const pidFile = path.join(stateDir, \"dev-services-runner-pids.json\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-services.ts","line":101,"snippet":"await writeFile(pidFile, JSON.stringify(payload, null, 2));","matchedPattern":"file read/write","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-services.ts","line":110,"snippet":"const raw = await readFile(pidFile, \"utf8\");","matchedPattern":"file read/write","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev-services.ts","line":121,"snippet":".join(\", \")}`","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev.ts","line":20,"snippet":"const stateDir = path.join(process.cwd(), \".tmp\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev.ts","line":21,"snippet":"const pidFile = path.join(stateDir, \"dev-runner-pids.json\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev.ts","line":102,"snippet":"await writeFile(pidFile, JSON.stringify(payload, null, 2));","matchedPattern":"file read/write","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev.ts","line":111,"snippet":"const raw = await readFile(pidFile, \"utf8\");","matchedPattern":"file read/write","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev.ts","line":122,"snippet":".join(\", \")}`","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev.ts","line":148,"snippet":"): { host: string; port: number } => {","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev.ts","line":151,"snippet":"return { host: fallbackHost, port: fallbackPort };","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev.ts","line":157,"snippet":"return { host: url.hostname || fallbackHost, port };","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev.ts","line":159,"snippet":"return { host: fallbackHost, port: fallbackPort };","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev.ts","line":163,"snippet":"const checkTcp = (host: string, port: number, timeoutMs = 1000): Promise<boolean> => {","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev.ts","line":165,"snippet":"const socket = net.connect({ host, port });","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/dev.ts","line":169,"snippet":"resolve(ok);","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"scripts/dev.ts","line":181,"snippet":"const response = await fetch(url);","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev.ts","line":296,"snippet":"checkTcp(natsTarget.host, natsTarget.port),","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"scripts/dev.ts","line":297,"snippet":"checkTcp(redisTarget.host, redisTarget.port),","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/sync-docker-workspace.ts","line":4,"snippet":"const repoRoot = path.resolve(import.meta.dir, \"..\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/sync-docker-workspace.ts","line":5,"snippet":"const deploymentRoot = path.join(repoRoot, \"deployment/docker/workspace-root\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/sync-docker-workspace.ts","line":14,"snippet":"const source = path.join(repoRoot, fileName);","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"scripts/sync-docker-workspace.ts","line":15,"snippet":"const destination = path.join(deploymentRoot, fileName);","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/src/contracts.ts","line":22,"snippet":"const expiry = expiryParts.join(\"-\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/src/contracts.ts","line":23,"snippet":"const root = parts.slice(0, -5).join(\"-\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/src/index.ts","line":904,"snippet":"features.conditions = Array.from(cluster.conditions).sort().join(\",\");","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/src/structure-packets.ts","line":221,"snippet":"const id = `flowpacket:${pseudoContractId}:${bucketStartTs}:${contractIds.join(\"|\")}`;","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/src/structure-packets.ts","line":222,"snippet":"const dedupeKey = `${pseudoContractId}:${bucketStartTs}:${contractIds.join(\"|\")}`;","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/src/structure-packets.ts","line":298,"snippet":"structure_contract_ids: summary.contractIds.join(\",\"),","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/src/structure-packets.ts","line":300,"snippet":"structure_expiries: plan.expiries.join(\",\"),","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/src/structure-packets.ts","line":301,"snippet":"structure_strikes_list: plan.strikes.join(\",\")","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/compute/tests/classifiers.test.ts","line":10,"snippet":"expect(hit.explanations.join(\" \")).toMatch(/Likely|Consistent with|Unusual/i);","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/ingest-equities/src/adapters/alpaca.ts","line":151,"snippet":"return `${parsed.origin}/v2/${feed}`;","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"services/ingest-equities/src/adapters/alpaca.ts","line":158,"snippet":"const response = await fetch(url.toString(), {","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"services/ingest-news/src/index.ts","line":109,"snippet":"const response = await fetch(url.toString(), {","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/ingest-options/py/databento_replay.py","line":106,"snippet":"response = self._client.symbology.resolve(","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/ingest-options/py/databento_replay.py","line":119,"snippet":"return self._map.resolve(instrument_id, date)","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/ingest-options/py/ibkr_stream.py","line":13,"snippet":"parser.add_argument(\"--host\", required=True)","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/ingest-options/py/ibkr_stream.py","line":39,"snippet":"ib.connect(args.host, args.port, clientId=args.client_id)","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"ssrf-capable-request","description":"Outbound HTTP request site that may be attacker-controlled.","noise":"normal","filePath":"services/ingest-options/src/adapters/alpaca.ts","line":159,"snippet":"const response = await fetch(url.toString(), {","matchedPattern":"fetch/http client","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/ingest-options/src/adapters/ibkr.ts","line":4,"snippet":"host: string;","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/ingest-options/src/adapters/ibkr.ts","line":72,"snippet":"\"--host\",","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/ingest-options/src/adapters/ibkr.ts","line":73,"snippet":"config.host,","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"hidden-control-channel","description":"Request header or framework/proxy context read that may influence auth, routing, tenant, runtime, debug, or middleware behavior.","noise":"normal","filePath":"services/ingest-options/src/index.ts","line":337,"snippet":"host: env.IBKR_HOST,","matchedPattern":"proxy or original request header","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/refdata/tests/event-calendar.test.ts","line":42,"snippet":"].join(\"\\n\"),","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"path-traversal-file-access","description":"Filesystem access using path joins or user-controllable paths.","noise":"normal","filePath":"services/replay/src/index.ts","line":173,"snippet":"throw new Error(`Unknown replay stream(s): ${invalid.join(\", \")}`);","matchedPattern":"path join","score":55,"source":"builtin"}
{"slug":"raw-sql-query","description":"Raw SQL construction or query execution that may need parameterization review.","noise":"normal","filePath":"services/replay/src/index.ts","line":306,"snippet":"await clickhouse.query({ query: \"SELECT 1\", format: \"JSONEachRow\" });","matchedPattern":"query call","score":55,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"apps/web/app/api/admin/synthetic/routes.test.ts","line":35,"snippet":"expect(new Headers(init?.headers).get(\"authorization\")).toBe(\"Bearer secret-token\");","matchedPattern":"http route","score":54,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"apps/web/app/api/admin/synthetic/shared.ts","line":60,"snippet":"\"content-type\": response.headers.get(\"content-type\") ?? \"application/json\"","matchedPattern":"http route","score":46,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"scripts/check-public-api-routes.ts","line":20,"snippet":"return (response.headers.get(\"content-type\") ?? \"\").toLowerCase().includes(\"application/json\");","matchedPattern":"http route","score":46,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"scripts/check-public-api-routes.ts","line":34,"snippet":"throw new Error(`${url.pathname} returned non-JSON content (${response.headers.get(\"content-type\") ?? \"none\"}): ${sample}`);","matchedPattern":"http route","score":46,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":328,"snippet":"const authorization = req.headers.get(\"authorization\") ?? \"\";","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":332,"snippet":"return req.headers.get(\"x-synthetic-admin-token\")?.trim() ?? \"\";","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":380,"snippet":"after_ts: url.searchParams.get(\"after_ts\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":381,"snippet":"after_seq: url.searchParams.get(\"after_seq\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":382,"snippet":"limit: url.searchParams.get(\"limit\") ?? undefined","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":394,"snippet":"before_ts: url.searchParams.get(\"before_ts\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":395,"snippet":"before_seq: url.searchParams.get(\"before_seq\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":396,"snippet":"limit: url.searchParams.get(\"limit\") ?? undefined","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":407,"snippet":"const raw = url.searchParams.get(\"source\");","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":432,"snippet":"underlying_id: url.searchParams.get(\"underlying_id\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":433,"snippet":"start_ts: url.searchParams.get(\"start_ts\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":434,"snippet":"end_ts: url.searchParams.get(\"end_ts\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":435,"snippet":"limit: url.searchParams.get(\"limit\") ?? undefined","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":457,"snippet":"underlying_id: url.searchParams.get(\"underlying_id\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":458,"snippet":"interval_ms: url.searchParams.get(\"interval_ms\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":459,"snippet":"start_ts: url.searchParams.get(\"start_ts\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":460,"snippet":"end_ts: url.searchParams.get(\"end_ts\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":461,"snippet":"limit: url.searchParams.get(\"limit\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":462,"snippet":"cache: url.searchParams.get(\"cache\") ?? undefined","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/index.ts","line":486,"snippet":"underlying_id: url.searchParams.get(\"underlying_id\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/live.ts","line":811,"snippet":"const cached = (this.genericItems.get(\"options\") ?? [])","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/live.ts","line":830,"snippet":"const items = (this.genericItems.get(\"options\") ?? [])","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/live.ts","line":844,"snippet":"const items = (this.genericItems.get(\"flow\") ?? [])","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/live.ts","line":858,"snippet":"const cached = (this.genericItems.get(\"equities\") ?? [])","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/live.ts","line":876,"snippet":"const items = (this.genericItems.get(\"equities\") ?? []).slice(0, limit);","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/option-queries.ts","line":63,"snippet":"view: url.searchParams.get(\"view\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/option-queries.ts","line":64,"snippet":"security: url.searchParams.get(\"security\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/option-queries.ts","line":65,"snippet":"side: url.searchParams.get(\"side\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/option-queries.ts","line":66,"snippet":"type: url.searchParams.get(\"type\") ?? undefined,","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/option-queries.ts","line":67,"snippet":"min_notional: url.searchParams.get(\"min_notional\") ?? undefined","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"services/api/src/option-queries.ts","line":71,"snippet":"optionContractId: url.searchParams.get(\"option_contract_id\") ?? undefined","matchedPattern":"http route","score":38,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"apps/web/app/terminal.test.ts","line":136,"snippet":"expect(evidence.packets.get(\"flowpacket:1\")).toBe(packet);","matchedPattern":"http route","score":30,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"apps/web/app/terminal.test.ts","line":137,"snippet":"expect(evidence.prints.get(\"print:1\")?.execution_nbbo_bid).toBe(1.2);","matchedPattern":"http route","score":30,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"apps/web/app/terminal.test.ts","line":138,"snippet":"expect(evidence.prints.get(\"print:1\")?.execution_underlying_spot).toBe(450.05);","matchedPattern":"http route","score":30,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"apps/web/app/terminal.tsx","line":516,"snippet":"const contentType = response.headers.get(\"content-type\")?.toLowerCase() ?? \"\";","matchedPattern":"http route","score":30,"source":"builtin"}
{"slug":"public-entrypoint","description":"Public route, handler, controller, workflow, or operation entry point.","noise":"noisy","filePath":"apps/web/app/terminal.tsx","line":6234,"snippet":"const contentType = response.headers.get(\"content-type\")?.toLowerCase() ?? \"\";","matchedPattern":"http route","score":30,"source":"builtin"}

View file

@ -0,0 +1,35 @@
{
"single_service": false,
"services": [
{"name":"web","root":"apps/web/","language":"typescript","frameworks":["nextjs"]},
{"name":"api","root":"services/api/","language":"typescript","frameworks":["bun","websocket"]},
{"name":"ingest-options","root":"services/ingest-options/","language":"typescript","frameworks":["nats","clickhouse"]},
{"name":"ingest-equities","root":"services/ingest-equities/","language":"typescript","frameworks":["nats","clickhouse"]},
{"name":"ingest-news","root":"services/ingest-news/","language":"typescript","frameworks":["nats"]},
{"name":"compute","root":"services/compute/","language":"typescript","frameworks":["nats","clickhouse"]},
{"name":"candles","root":"services/candles/","language":"typescript","frameworks":["nats","clickhouse","redis"]},
{"name":"replay","root":"services/replay/","language":"typescript","frameworks":["nats"]}
],
"edges": [
{"id":"E001","channel":"http","producer":{"service":"web","file":"apps/web/app/api/admin/synthetic/shared.ts","line":51,"pattern":"fetch(url.toString(), { method, headers, body })"},"consumer":{"service":"api","file":"services/api/src/index.ts","line":1364,"pattern":"GET/PUT /admin/synthetic/*"},"data_shape":"admin synthetic status/control HTTP JSON body proxied from browser","sanitization_at_boundary":"API bearer token check; no browser-user auth in web proxy per authz matrix","trust_tagged":"web injects SYNTHETIC_ADMIN_TOKEN for caller"},
{"id":"E002","channel":"queue:options.prints","producer":{"service":"ingest-options","file":"services/ingest-options/src/index.ts","line":430,"pattern":"publishJson(js, SUBJECT_OPTION_PRINTS, print)"},"consumer":{"service":"replay/external","file":"packages/bus/src/subjects.ts","line":2,"pattern":"SUBJECT_OPTION_PRINTS = 'options.prints'"},"data_shape":"OptionPrint JSON","sanitization_at_boundary":"OptionPrintSchema.parse before publish; consumers schema-parse when present","trust_tagged":"none"},
{"id":"E003","channel":"queue:options.prints.signal","producer":{"service":"ingest-options","file":"services/ingest-options/src/index.ts","line":432,"pattern":"publishJson(js, SUBJECT_OPTION_SIGNAL_PRINTS, print)"},"consumer":{"service":"compute","file":"services/compute/src/index.ts","line":1501,"pattern":"subscribeJson(js, SUBJECT_OPTION_SIGNAL_PRINTS, opts)"},"data_shape":"signal-passing OptionPrint JSON","sanitization_at_boundary":"producer and compute parse OptionPrintSchema; no message authentication","trust_tagged":"signal_pass flag controls downstream processing"},
{"id":"E004","channel":"queue:options.prints.signal","producer":{"service":"ingest-options/replay","file":"services/replay/src/index.ts","line":407,"pattern":"publishJson(js, SUBJECT_OPTION_SIGNAL_PRINTS, event as OptionPrint)"},"consumer":{"service":"api","file":"services/api/src/index.ts","line":945,"pattern":"subscribeWithReset(SUBJECT_OPTION_SIGNAL_PRINTS, ...)"},"data_shape":"OptionPrint JSON for live API fanout","sanitization_at_boundary":"consumer OptionPrintSchema.parse in pump; no message authentication","trust_tagged":"none"},
{"id":"E005","channel":"queue:options.nbbo","producer":{"service":"ingest-options","file":"services/ingest-options/src/index.ts","line":460,"pattern":"publishJson(js, SUBJECT_OPTION_NBBO, nbbo)"},"consumer":{"service":"compute","file":"services/compute/src/index.ts","line":1537,"pattern":"subscribeJson(js, SUBJECT_OPTION_NBBO, opts)"},"data_shape":"OptionNBBO JSON","sanitization_at_boundary":"schema parse both ends; no message authentication","trust_tagged":"none"},
{"id":"E006","channel":"queue:equities.prints","producer":{"service":"ingest-equities","file":"services/ingest-equities/src/index.ts","line":266,"pattern":"publishJson(js, SUBJECT_EQUITY_PRINTS, print)"},"consumer":{"service":"compute","file":"services/compute/src/index.ts","line":1573,"pattern":"subscribeJson(js, SUBJECT_EQUITY_PRINTS, opts)"},"data_shape":"EquityPrint JSON","sanitization_at_boundary":"schema parse both ends; no message authentication","trust_tagged":"none"},
{"id":"E007","channel":"queue:equities.prints","producer":{"service":"ingest-equities","file":"services/ingest-equities/src/index.ts","line":266,"pattern":"publishJson(js, SUBJECT_EQUITY_PRINTS, print)"},"consumer":{"service":"candles","file":"services/candles/src/index.ts","line":341,"pattern":"subscribeJson(js, SUBJECT_EQUITY_PRINTS, resetOpts)"},"data_shape":"EquityPrint JSON","sanitization_at_boundary":"consumer EquityPrintSchema.parse; no message authentication","trust_tagged":"none"},
{"id":"E008","channel":"queue:equities.quotes","producer":{"service":"ingest-equities","file":"services/ingest-equities/src/index.ts","line":292,"pattern":"publishJson(js, SUBJECT_EQUITY_QUOTES, quote)"},"consumer":{"service":"ingest-options","file":"services/ingest-options/src/index.ts","line":476,"pattern":"subscribeJson<EquityQuote>(js, SUBJECT_EQUITY_QUOTES, ...)"},"data_shape":"EquityQuote JSON used to enrich option prints","sanitization_at_boundary":"schema parse at producer; consumer subscribes and later validates context; no message authentication","trust_tagged":"none"},
{"id":"E009","channel":"queue:equities.candles","producer":{"service":"candles","file":"services/candles/src/index.ts","line":188,"pattern":"publishJson(js, SUBJECT_EQUITY_CANDLES, candle)"},"consumer":{"service":"api","file":"services/api/src/index.ts","line":963,"pattern":"subscribeWithReset(SUBJECT_EQUITY_CANDLES, ...)"},"data_shape":"EquityCandle JSON for live fanout","sanitization_at_boundary":"candle schema parse before emit and API parse; no message authentication","trust_tagged":"none"},
{"id":"E010","channel":"queue:flow.packets","producer":{"service":"compute","file":"services/compute/src/index.ts","line":574,"pattern":"publishJson(js, SUBJECT_FLOW_PACKETS, validated)"},"consumer":{"service":"api","file":"services/api/src/index.ts","line":987,"pattern":"subscribeWithReset(SUBJECT_FLOW_PACKETS, ...)"},"data_shape":"FlowPacket JSON for storage/live fanout","sanitization_at_boundary":"schema parse before publish and in API; no message authentication","trust_tagged":"none"},
{"id":"E011","channel":"queue:flow.smart_money","producer":{"service":"compute","file":"services/compute/src/index.ts","line":1083,"pattern":"publishJson(js, SUBJECT_SMART_MONEY_EVENTS, smartMoneyEvent)"},"consumer":{"service":"api","file":"services/api/src/index.ts","line":993,"pattern":"subscribeWithReset(SUBJECT_SMART_MONEY_EVENTS, ...)"},"data_shape":"SmartMoneyEvent JSON","sanitization_at_boundary":"schema parse; no message authentication","trust_tagged":"none"},
{"id":"E012","channel":"queue:flow.classifier_hits","producer":{"service":"compute","file":"services/compute/src/index.ts","line":1114,"pattern":"publishJson(js, SUBJECT_CLASSIFIER_HITS, hit)"},"consumer":{"service":"api","file":"services/api/src/index.ts","line":999,"pattern":"subscribeWithReset(SUBJECT_CLASSIFIER_HITS, ...)"},"data_shape":"ClassifierHitEvent JSON","sanitization_at_boundary":"schema parse; no message authentication","trust_tagged":"none"},
{"id":"E013","channel":"queue:flow.alerts","producer":{"service":"compute","file":"services/compute/src/index.ts","line":1151,"pattern":"publishJson(js, SUBJECT_ALERTS, alert)"},"consumer":{"service":"api","file":"services/api/src/index.ts","line":1005,"pattern":"subscribeWithReset(SUBJECT_ALERTS, ...)"},"data_shape":"AlertEvent JSON","sanitization_at_boundary":"schema parse; no message authentication","trust_tagged":"none"},
{"id":"E014","channel":"queue:flow.news","producer":{"service":"ingest-news","file":"services/ingest-news/src/index.ts","line":158,"pattern":"publishJson(js, SUBJECT_NEWS, story)"},"consumer":{"service":"api","file":"services/api/src/index.ts","line":1281,"pattern":"NewsStorySchema.parse(...); insertNewsStory(clickhouse, payload); fanoutLive(...)"},"data_shape":"NewsStory JSON from external Alpaca news feed","sanitization_at_boundary":"NewsStorySchema.parse only; no NATS subject-level source authentication in compose","trust_tagged":"NATS subject name implies trusted ingest-news origin"},
{"id":"E015","channel":"db-table:news","producer":{"service":"api","file":"services/api/src/index.ts","line":1281,"pattern":"insertNewsStory(clickhouse, payload)"},"consumer":{"service":"api/web","file":"packages/storage/src/clickhouse.ts","line":1289,"pattern":"FROM news"},"data_shape":"persisted NewsStory columns served by /news/history/news","sanitization_at_boundary":"ClickHouse insert/read typed; UI rendering not re-derived here","trust_tagged":"database as durable trust boundary"}
],
"coverage_gaps": [
{"reason":"third-party/external HTTP client calls excluded from internal edge findings","location":"services/ingest-news/src/index.ts:109; services/ingest-equities/src/adapters/alpaca.ts:158; services/ingest-options/src/adapters/alpaca.ts:159","expression":"fetch(provider URLs)"},
{"reason":"unmatched in-repo producer or consumer for raw options.prints stream; likely storage/replay or external consumer","location":"services/ingest-options/src/index.ts:430","expression":"SUBJECT_OPTION_PRINTS"},
{"reason":"Docker compose NATS command has JetStream only and no auth/ACL/TLS flags","location":"deployment/docker/docker-compose.yml:166","expression":"command: ['-js', '-sd', '/data']"}
]
}

View file

@ -0,0 +1,27 @@
# Cross-Service Edges
Multi-service topology confirmed from `services/*`, `apps/*`, shared `packages/*`, and `deployment/docker/docker-compose.yml`.
| Edge | Channel | Producer | Consumer | Data shape | Boundary notes |
|---|---|---|---|---|---|
| E001 | http | web `apps/web/app/api/admin/synthetic/shared.ts:51` | api `services/api/src/index.ts:1364` | admin synthetic JSON | web injects admin bearer token; see p5 authz finding |
| E002 | queue `options.prints` | ingest-options `services/ingest-options/src/index.ts:430` | unmatched/external | `OptionPrint` | schema parse before publish; no message auth observed |
| E003 | queue `options.prints.signal` | ingest-options `services/ingest-options/src/index.ts:432` | compute `services/compute/src/index.ts:1501` | signal `OptionPrint` | signal flag trusted across NATS |
| E004 | queue `options.prints.signal` | ingest-options/replay `services/replay/src/index.ts:407` | api `services/api/src/index.ts:945` | live option print | schema parse in API; no message auth observed |
| E005 | queue `options.nbbo` | ingest-options `services/ingest-options/src/index.ts:460` | compute `services/compute/src/index.ts:1537` | `OptionNBBO` | schema parse; no message auth observed |
| E006 | queue `equities.prints` | ingest-equities `services/ingest-equities/src/index.ts:266` | compute `services/compute/src/index.ts:1573` | `EquityPrint` | schema parse; no message auth observed |
| E007 | queue `equities.prints` | ingest-equities `services/ingest-equities/src/index.ts:266` | candles `services/candles/src/index.ts:341` | `EquityPrint` | schema parse; no message auth observed |
| E008 | queue `equities.quotes` | ingest-equities `services/ingest-equities/src/index.ts:292` | ingest-options `services/ingest-options/src/index.ts:476` | `EquityQuote` | used as enrichment context |
| E009 | queue `equities.candles` | candles `services/candles/src/index.ts:188` | api `services/api/src/index.ts:963` | `EquityCandle` | live fanout and storage path |
| E010 | queue `flow.packets` | compute `services/compute/src/index.ts:574` | api `services/api/src/index.ts:987` | `FlowPacket` | derived analytics live/storage path |
| E011 | queue `flow.smart_money` | compute `services/compute/src/index.ts:1083` | api `services/api/src/index.ts:993` | `SmartMoneyEvent` | derived analytics live/storage path |
| E012 | queue `flow.classifier_hits` | compute `services/compute/src/index.ts:1114` | api `services/api/src/index.ts:999` | `ClassifierHitEvent` | derived analytics live/storage path |
| E013 | queue `flow.alerts` | compute `services/compute/src/index.ts:1151` | api `services/api/src/index.ts:1005` | `AlertEvent` | broadcast/fanout path |
| E014 | queue `flow.news` | ingest-news `services/ingest-news/src/index.ts:158` | api `services/api/src/index.ts:1281` | `NewsStory` | API persists and fans out news; no NATS auth/ACL in compose |
| E015 | db table `news` | api `services/api/src/index.ts:1281` | API/web via storage `packages/storage/src/clickhouse.ts:1289` | persisted news | durable dataflow through ClickHouse |
## Coverage gaps
- Provider HTTP calls are external (`Alpaca`/market data) and were not treated as internal service edges.
- Raw `options.prints` has a producer but no in-repo durable consumer identified in this pass.
- NATS is configured in compose as `nats -js -sd /data` with no auth/ACL/TLS flags; queue source identity is therefore a cross-service trust assumption.

View file

@ -0,0 +1,34 @@
{
"summaryPath": "piolium/attack-surface/deep-cleanup-summary.json",
"removed": [
"piolium/tmp",
"piolium/chamber-workspace",
"piolium/adversarial-reviews",
"piolium/bypass-analysis",
"piolium/codeql-artifacts",
"piolium/codeql-queries",
"piolium/semgrep-rules",
"piolium/confirm-workspace",
"piolium/real-env-evidence",
"piolium/findings-draft"
],
"missing": [
"piolium/probe-workspace",
"piolium/agentic-actions-res",
"piolium/codeql-res",
"piolium/semgrep-res",
"piolium/raw",
"piolium/file-records",
"piolium/attack-surface/raw",
"piolium/attack-pattern-registry.json",
"piolium/authz-coverage-gaps.md",
"piolium/merged-results.sarif"
],
"retained": [
"piolium/attack-surface/",
"piolium/findings/",
"piolium/final-audit-report.md",
"piolium/confirmation-report.md",
"piolium/audit-state.json"
]
}

View file

@ -0,0 +1,34 @@
# Stage 08 Manual Attack Surface Probe Summary
Status: complete
Mode: single-team MVP
Inventory: `piolium/attack-surface/manual-attack-surface-inventory.md`
## Sources reviewed
- `piolium/attack-surface/knowledge-base-report.md`
- `piolium/attack-surface/candidates-summary.md`
- P3-P7 artifacts: public route authz matrix, source/sink flows, spec gap summary, state/concurrency summary
- Source files for selected slices: `services/api/src/index.ts`, `apps/web/app/api/admin/synthetic/**`, `apps/web/app/terminal.tsx`, `services/ingest-news/src/index.ts`, `docker-compose.yml`
## Inline hypotheses and verification
| ID | Reasoning | Hypothesis | Verification result | Draft |
|---|---|---|---|---|
| H1 | Backward | If synthetic admin control is high-impact, look backward from `writeSyntheticControlState` to see whether every caller is authenticated as an admin user. | Validated: API requires bearer token, but Next public route injects that token for any caller when enabled (`shared.ts:25-55`; route handlers at `status/route.ts:5-7`, `control/route.ts:5-17`; API mutation at `index.ts:1380-1388`). | `piolium/findings-draft/p8-001-public-next-admin-proxy-synthetic-control.md` |
| H2 | Backward | If provider-controlled HTML can execute in the browser, trace from feed `content` to DOM sinks. | Validated as fragile stored-XSS boundary: `item.content` becomes `content_html` (`ingest-news/src/index.ts:76-96`), regex sanitizer is used (`terminal.tsx:1272-1287`), then `dangerouslySetInnerHTML` (`terminal.tsx:5008-5009`). | `piolium/findings-draft/p8-002-provider-news-html-regex-sanitizer-xss.md` |
| H3 | Contradiction | The system assumes infra is internal-only; check for a deployment artifact that contradicts this by publishing internal services. | Validated: root compose publishes ClickHouse `8123/9000`, Redis `6379`, and NATS `4222/8222` without credentials/TLS/ACLs visible (`docker-compose.yml:4-24`). | `piolium/findings-draft/p8-003-root-compose-exposes-unauthenticated-infrastructure.md` |
| H4 | Contradiction | The API relies on deployment perimeter for proprietary data; check whether WS route code enforces auth/origin if perimeter is absent. | Validated: WS upgrades happen by path only (`services/api/src/index.ts:1846-1936`); live messages can subscribe and receive snapshots without auth (`index.ts:1982-2008`). | `piolium/findings-draft/p8-004-unauthenticated-websocket-market-streams.md` |
## Coverage by slice
| Slice | Public routes / channels | Attacker source | Sink | Result |
|---|---|---|---|---|
| Synthetic admin | `/api/admin/synthetic/*`, `/admin/synthetic/*` | Anonymous browser + feature/env enabled | NATS KV synthetic control | Finding drafted P8-001 |
| News HTML | `/history/news`, UI news drawer | Provider `item.content` | Browser DOM `dangerouslySetInnerHTML` | Finding drafted P8-002 |
| Infra services | Host ports `8123`, `9000`, `6379`, `4222`, `8222` | Network client | ClickHouse/Redis/NATS | Finding drafted P8-003 |
| WebSockets | `/ws/*`, `/ws/live` | Anonymous WS client / cross-site browser | Live broadcasts/snapshots | Finding drafted P8-004 |
| REST history/replay | `/history/*`, `/replay/*` | Anonymous HTTP query params | ClickHouse query reads | Already covered by previous P4/P5; not re-drafted except WS focus |
## Notes
- Several P8 findings intentionally promote/refresh earlier P4-P7 candidates with manual file:line evidence, as requested for Stage 08 drafts.
- No SQL injection was promoted in this pass; prior artifacts show query builders commonly use zod parsing, clamps, and quote helpers, while the higher-impact verified paths above had clearer exploitability.

View file

@ -0,0 +1,73 @@
./apps/desktop/package.json @electron-forge/cli ^7.8.1
./apps/desktop/package.json @electron-forge/core ^7.11.1
./apps/desktop/package.json @electron-forge/maker-zip ^7.8.1
./apps/desktop/package.json @types/node ^24.10.1
./apps/desktop/package.json electron ^39.2.0
./apps/desktop/package.json typescript ^5.9.3
./apps/web/package.json @islandflow/types workspace:*
./apps/web/package.json @tanstack/react-virtual ^3.13.24
./apps/web/package.json lightweight-charts ^4.2.0
./apps/web/package.json next ^16.2.6
./apps/web/package.json react ^19.2.0
./apps/web/package.json react-dom ^19.2.0
./deployment/docker/workspace-root/package.json @pierre/diffs ^1.2.2
./package.json @pierre/diffs ^1.2.2
./packages/bus/package.json @islandflow/types workspace:*
./packages/bus/package.json nats ^2.24.0
./packages/config/package.json zod ^3.23.8
./packages/storage/package.json @clickhouse/client ^0.2.6
./packages/storage/package.json @islandflow/types workspace:*
./packages/types/package.json zod ^3.23.8
./services/api/package.json @islandflow/bus workspace:*
./services/api/package.json @islandflow/config workspace:*
./services/api/package.json @islandflow/observability workspace:*
./services/api/package.json @islandflow/storage workspace:*
./services/api/package.json @islandflow/types workspace:*
./services/api/package.json redis ^5.10.0
./services/api/package.json zod ^3.23.8
./services/candles/package.json @islandflow/bus workspace:*
./services/candles/package.json @islandflow/config workspace:*
./services/candles/package.json @islandflow/observability workspace:*
./services/candles/package.json @islandflow/storage workspace:*
./services/candles/package.json @islandflow/types workspace:*
./services/candles/package.json redis ^5.10.0
./services/candles/package.json zod ^3.23.8
./services/compute/package.json @islandflow/bus workspace:*
./services/compute/package.json @islandflow/config workspace:*
./services/compute/package.json @islandflow/observability workspace:*
./services/compute/package.json @islandflow/refdata workspace:*
./services/compute/package.json @islandflow/storage workspace:*
./services/compute/package.json @islandflow/types workspace:*
./services/compute/package.json redis ^5.10.0
./services/compute/package.json zod ^3.23.8
./services/eod-enricher/package.json @islandflow/config workspace:*
./services/eod-enricher/package.json @islandflow/observability workspace:*
./services/ingest-equities/package.json @islandflow/bus workspace:*
./services/ingest-equities/package.json @islandflow/config workspace:*
./services/ingest-equities/package.json @islandflow/observability workspace:*
./services/ingest-equities/package.json @islandflow/storage workspace:*
./services/ingest-equities/package.json @islandflow/types workspace:*
./services/ingest-equities/package.json ws ^8.21.0
./services/ingest-equities/package.json zod ^3.23.8
./services/ingest-news/package.json @islandflow/bus workspace:*
./services/ingest-news/package.json @islandflow/config workspace:*
./services/ingest-news/package.json @islandflow/observability workspace:*
./services/ingest-news/package.json @islandflow/types workspace:*
./services/ingest-news/package.json ws ^8.21.0
./services/ingest-news/package.json zod ^3.23.8
./services/ingest-options/package.json @islandflow/bus workspace:*
./services/ingest-options/package.json @islandflow/config workspace:*
./services/ingest-options/package.json @islandflow/observability workspace:*
./services/ingest-options/package.json @islandflow/storage workspace:*
./services/ingest-options/package.json @islandflow/types workspace:*
./services/ingest-options/package.json @msgpack/msgpack ^3.1.3
./services/ingest-options/package.json ws ^8.21.0
./services/ingest-options/package.json zod ^3.23.8
./services/refdata/package.json @islandflow/config workspace:*
./services/refdata/package.json @islandflow/observability workspace:*
./services/replay/package.json @islandflow/bus workspace:*
./services/replay/package.json @islandflow/config workspace:*
./services/replay/package.json @islandflow/observability workspace:*
./services/replay/package.json @islandflow/storage workspace:*
./services/replay/package.json @islandflow/types workspace:*
./services/replay/package.json zod ^3.23.8
1 ./apps/desktop/package.json @electron-forge/cli ^7.8.1
2 ./apps/desktop/package.json @electron-forge/core ^7.11.1
3 ./apps/desktop/package.json @electron-forge/maker-zip ^7.8.1
4 ./apps/desktop/package.json @types/node ^24.10.1
5 ./apps/desktop/package.json electron ^39.2.0
6 ./apps/desktop/package.json typescript ^5.9.3
7 ./apps/web/package.json @islandflow/types workspace:*
8 ./apps/web/package.json @tanstack/react-virtual ^3.13.24
9 ./apps/web/package.json lightweight-charts ^4.2.0
10 ./apps/web/package.json next ^16.2.6
11 ./apps/web/package.json react ^19.2.0
12 ./apps/web/package.json react-dom ^19.2.0
13 ./deployment/docker/workspace-root/package.json @pierre/diffs ^1.2.2
14 ./package.json @pierre/diffs ^1.2.2
15 ./packages/bus/package.json @islandflow/types workspace:*
16 ./packages/bus/package.json nats ^2.24.0
17 ./packages/config/package.json zod ^3.23.8
18 ./packages/storage/package.json @clickhouse/client ^0.2.6
19 ./packages/storage/package.json @islandflow/types workspace:*
20 ./packages/types/package.json zod ^3.23.8
21 ./services/api/package.json @islandflow/bus workspace:*
22 ./services/api/package.json @islandflow/config workspace:*
23 ./services/api/package.json @islandflow/observability workspace:*
24 ./services/api/package.json @islandflow/storage workspace:*
25 ./services/api/package.json @islandflow/types workspace:*
26 ./services/api/package.json redis ^5.10.0
27 ./services/api/package.json zod ^3.23.8
28 ./services/candles/package.json @islandflow/bus workspace:*
29 ./services/candles/package.json @islandflow/config workspace:*
30 ./services/candles/package.json @islandflow/observability workspace:*
31 ./services/candles/package.json @islandflow/storage workspace:*
32 ./services/candles/package.json @islandflow/types workspace:*
33 ./services/candles/package.json redis ^5.10.0
34 ./services/candles/package.json zod ^3.23.8
35 ./services/compute/package.json @islandflow/bus workspace:*
36 ./services/compute/package.json @islandflow/config workspace:*
37 ./services/compute/package.json @islandflow/observability workspace:*
38 ./services/compute/package.json @islandflow/refdata workspace:*
39 ./services/compute/package.json @islandflow/storage workspace:*
40 ./services/compute/package.json @islandflow/types workspace:*
41 ./services/compute/package.json redis ^5.10.0
42 ./services/compute/package.json zod ^3.23.8
43 ./services/eod-enricher/package.json @islandflow/config workspace:*
44 ./services/eod-enricher/package.json @islandflow/observability workspace:*
45 ./services/ingest-equities/package.json @islandflow/bus workspace:*
46 ./services/ingest-equities/package.json @islandflow/config workspace:*
47 ./services/ingest-equities/package.json @islandflow/observability workspace:*
48 ./services/ingest-equities/package.json @islandflow/storage workspace:*
49 ./services/ingest-equities/package.json @islandflow/types workspace:*
50 ./services/ingest-equities/package.json ws ^8.21.0
51 ./services/ingest-equities/package.json zod ^3.23.8
52 ./services/ingest-news/package.json @islandflow/bus workspace:*
53 ./services/ingest-news/package.json @islandflow/config workspace:*
54 ./services/ingest-news/package.json @islandflow/observability workspace:*
55 ./services/ingest-news/package.json @islandflow/types workspace:*
56 ./services/ingest-news/package.json ws ^8.21.0
57 ./services/ingest-news/package.json zod ^3.23.8
58 ./services/ingest-options/package.json @islandflow/bus workspace:*
59 ./services/ingest-options/package.json @islandflow/config workspace:*
60 ./services/ingest-options/package.json @islandflow/observability workspace:*
61 ./services/ingest-options/package.json @islandflow/storage workspace:*
62 ./services/ingest-options/package.json @islandflow/types workspace:*
63 ./services/ingest-options/package.json @msgpack/msgpack ^3.1.3
64 ./services/ingest-options/package.json ws ^8.21.0
65 ./services/ingest-options/package.json zod ^3.23.8
66 ./services/refdata/package.json @islandflow/config workspace:*
67 ./services/refdata/package.json @islandflow/observability workspace:*
68 ./services/replay/package.json @islandflow/bus workspace:*
69 ./services/replay/package.json @islandflow/config workspace:*
70 ./services/replay/package.json @islandflow/observability workspace:*
71 ./services/replay/package.json @islandflow/storage workspace:*
72 ./services/replay/package.json @islandflow/types workspace:*
73 ./services/replay/package.json zod ^3.23.8

View file

@ -0,0 +1,429 @@
# Islandflow Phase 3 Architecture & Threat Model KB
Generated for Stage 03 `/piolium-deep` on 2026-05-27. Evidence: `README.md`, `package.json`, `services/api/src/index.ts`, `packages/storage/src/clickhouse.ts`, `services/ingest-*`, `packages/bus`, `apps/web`, `apps/desktop`, and `deployment/docker/docker-compose.yml`.
## Project Classification
### Project Type
- **Web app**: `apps/web` is a Next.js 16 UI with public pages (`/`, `/tape`, `/signals`, `/charts`, `/news`, `/options`, `/replay`) and Next route handlers for synthetic-admin proxying.
- **API / WebSocket gateway**: `services/api` is a Bun HTTP server exposing REST history/live/replay endpoints and many WebSocket channels.
- **Workers / stream processors**: `services/ingest-options`, `services/ingest-equities`, `services/ingest-news`, `services/compute`, `services/candles`, `services/replay`, `services/refdata`.
- **Desktop app**: `apps/desktop` is an Electron wrapper around the hosted/local web app.
- **Internal libraries**: `packages/types`, `packages/storage`, `packages/bus`, `packages/config`, `packages/observability`.
- **Deployment/CI tooling**: Docker Compose VPS deployment, Bun scripts, Forgejo/GitHub Actions docs/workflows.
Purpose: personal-use, event-sourced market microstructure research platform that ingests external market/news feeds, normalizes/publishes events over NATS/JetStream, persists to ClickHouse/Redis, computes derived flow/smart-money artifacts, and exposes live/replay/history through REST and WebSockets.
## Architecture Model
### Components
| Component | Key files | Role | Security relevance |
|---|---|---|---|
| Next.js web | `apps/web/app/**`, `apps/web/app/api/admin/synthetic/**` | UI + admin proxy | Browser input, rendering news/market data, admin proxy token forwarding |
| API gateway | `services/api/src/index.ts` | Bun REST/WebSocket server | Main network boundary; auth only for synthetic admin; query params to ClickHouse; WS fanout/subscription handling |
| Storage | `packages/storage/src/clickhouse.ts` | ClickHouse schema, insert/fetch query builders | SQL string construction, cursor pagination, record normalization |
| Bus | `packages/bus/src/**` | NATS/JetStream streams, subjects, KV synthetic control | Internal message integrity boundary; subject abuse/replay risks |
| Ingest options | `services/ingest-options/src/**`, `py/*` | Alpaca ws/rest, Databento/IBKR Python sidecars, msgpack/json parsing | Untrusted third-party feed data and child-process stdout enter system |
| Ingest equities/news | `services/ingest-equities/src/**`, `services/ingest-news/src/index.ts` | Alpaca feed ingestion | WebSocket/REST parsing, news HTML/content propagation |
| Compute/candles/replay | `services/compute/src/**`, `services/candles/src/**`, `services/replay/src/index.ts` | Derived events and replay | Trusts NATS/ClickHouse inputs; can amplify poisoned data |
| Electron shell | `apps/desktop/src/main.ts`, `apps/desktop/src/security.ts` | Hosted/local app wrapper | Origin/navigation/sandbox boundary; env-controlled start URL |
| Infra | `deployment/docker/docker-compose.yml` | Web, API, NATS, ClickHouse, Redis | Bind addresses, unauthenticated internal services, secrets in env |
### Trust Boundaries
1. **Internet/browser -> Next.js web/API**: HTTP and WebSocket requests. Public API appears largely unauthenticated except synthetic admin endpoints.
2. **Next.js admin proxy -> API synthetic admin**: `apps/web/app/api/admin/synthetic/shared.ts` forwards `Authorization: Bearer ${SYNTHETIC_ADMIN_TOKEN}` to `NEXT_PUBLIC_API_URL`; feature gated by `NEXT_PUBLIC_SYNTHETIC_ADMIN=1`.
3. **External market/news providers -> ingest workers**: Alpaca REST/WS, Databento replay, IBKR bridge; data is untrusted until parsed/validated by zod/shared schemas.
4. **Python child processes -> TypeScript ingest**: `Bun.spawn` stdout JSON lines in Databento/IBKR adapters are untrusted local-process output and a command/argument construction boundary.
5. **Services -> NATS/JetStream**: internal event bus subjects determine which events reach compute/storage/API. No per-subject auth visible in compose (`nats -js -sd /data`).
6. **Services -> ClickHouse/Redis**: storage/cache boundary; query strings are manually built; Redis hot cache can affect live UI state.
7. **Electron shell -> remote/local web app -> external links**: trusted origins hardcoded; navigation guards route untrusted URLs to OS browser via `shell.openExternal`.
8. **Deployment edge/proxy -> containers**: Compose binds web/API to `127.0.0.1` by default and joins an external `npm-shared` network for reverse proxy. Security depends on edge routing and env overrides.
## DFD/CFD Slices
### DFD-1: Public API query params to ClickHouse history/replay
```mermaid
flowchart LR
A[Browser/API client] -->|GET /history/* /replay/* /prints/* query params| B[services/api Bun server]
B -->|zod/coerce parse limit/cursors/filters| C[storage fetch* functions]
C -->|manual SQL string + quoteString/clampLimit| D[(ClickHouse)]
D -->|JSONEachRow rows| B --> A
```
Risk: SQL injection if any string reaches query builder without `quoteString`; DoS via expensive ranges/large limits; data exposure because endpoints are unauthenticated.
### DFD-2: WebSocket live fanout/subscription filtering
```mermaid
flowchart LR
A[Browser WS client] -->|GET /ws/*; /ws/live messages| B[API websocket handler]
B -->|LiveClientMessageSchema / subscription state| C[LiveStateManager]
D[NATS events] --> E[API subscribers]
E -->|filter by subscription/channel| B --> A
```
Risk: unauthenticated streaming of potentially valuable feed/derived data; WS resource exhaustion; subscription filter bypass or malformed message DoS.
### DFD-3: External feeds to NATS/ClickHouse/UI
```mermaid
flowchart LR
A[Alpaca/Databento/IBKR/news feeds] -->|WS/REST/msgpack/JSON/child stdout| B[ingest workers]
B -->|schema parse/normalization| C[NATS subjects]
C --> D[compute/candles]
C --> E[storage writers]
E --> F[(ClickHouse)]
F --> G[API REST/WS] --> H[Web/Electron UI]
```
Risk: poisoned feed messages, malformed binary/JSON DoS, HTML/script content in news, bogus symbols/traces polluting derived analytics and UI.
### DFD-4: Synthetic admin control
```mermaid
flowchart LR
A[Browser] -->|/api/admin/synthetic/*| B[Next route handler]
B -->|Bearer SYNTHETIC_ADMIN_TOKEN| C[API /admin/synthetic/status/control]
C -->|writeSyntheticControlState| D[NATS KV synthetic control]
D --> E[synthetic ingest/backend mode]
```
Risk: token leakage/misconfiguration; SSRF-like proxying if `NEXT_PUBLIC_API_URL` is attacker-controlled; admin state changes control synthetic market behavior.
### DFD-5: Electron navigation
```mermaid
flowchart LR
A[Env ISLANDFLOW_DESKTOP_START_URL] --> B[resolveDesktopStartUrl]
B -->|trusted origin only| C[BrowserWindow]
C -->|will-navigate/window.open| D[Navigation guards]
D -->|trusted: load| C
D -->|external safe URL| E[OS browser shell.openExternal]
```
Risk: origin allowlist mistakes, openExternal abuse, remote content compromise; controls include sandbox, context isolation, no nodeIntegration, disabled permission requests.
### CFD-1: Request routing/auth decision in API
```mermaid
flowchart TD
A[Bun fetch(req)] --> B{path/method}
B -->|/health| Z[public ok]
B -->|/admin/synthetic/*| C[authenticateSyntheticAdminRequest]
C -->|fail| D[401/403]
C -->|pass| E[status/control KV]
B -->|all market/history/replay/ws paths| F[public handler no auth]
F --> G[parse params -> storage/WS]
```
Security-critical decision: only synthetic admin is protected; all other handlers rely on deployment/network exposure for access control.
### CFD-2: Ingest validation/control flow
```mermaid
flowchart TD
A[adapter selected by env] --> B{synthetic/alpaca/databento/ibkr}
B --> C[external REST/WS or Bun.spawn]
C --> D[decode JSON/msgpack/lines]
D --> E{schema/field checks}
E -->|valid| F[publishJson to NATS]
E -->|invalid| G[drop/log/continue]
```
Security-critical decision: schema parsing and field bounds decide whether untrusted external data becomes authoritative event stream.
### CFD-3: Deployment exposure
```mermaid
flowchart TD
A[.env / compose vars] --> B{WEB_BIND_IP/API_BIND_IP}
B -->|default 127.0.0.1| C[local reverse proxy boundary]
B -->|0.0.0.0 override| D[direct public exposure]
C --> E[external npm-shared network]
D --> F[public unauth API/WS if firewall absent]
```
Security-critical decision: production auth depends heavily on bind IP/reverse proxy/firewall settings.
## Attack Surface
### Attacker-controlled sources
- HTTP paths/query/body to `services/api` REST endpoints: `/prints/options`, `/nbbo/options`, `/prints/equities`, `/prints/equities/range`, `/quotes/equities`, `/candles/equities`, `/joins/equities`, `/dark/inferred`, `/flow/*`, `/news`, `/history/*`, `/replay/*`, `/lookup/options-support`, `/*/by-*`, `/flow/alerts/:trace/context`.
- WebSocket connections/messages to `/ws/options`, `/ws/options-nbbo`, `/ws/equities`, `/ws/equity-candles`, `/ws/equity-quotes`, `/ws/equity-joins`, `/ws/inferred-dark`, `/ws/flow`, `/ws/classifier-hits`, `/ws/smart-money`, `/ws/alerts`, `/ws/live`.
- Next.js route handlers `/api/admin/synthetic/status` and `/api/admin/synthetic/control` when admin feature enabled.
- Market/news provider payloads from Alpaca REST/WS, Databento replay output, IBKR bridge output.
- Environment variables: service URLs, bind IPs, tokens/API keys, Python binary path, adapter selection, Electron start URL.
- NATS messages/KV state if any service or network peer can publish.
- ClickHouse/Redis contents if storage is compromised or seeded with malicious data.
- CI/deploy script inputs: branch names, PR refs, env secrets, deployment hosts.
### High-value sinks
- ClickHouse query execution in `packages/storage/src/clickhouse.ts`.
- NATS publish/subscribe/KV in `packages/bus/src/**` and service consumers.
- Redis hot cache in `services/api/src/live.ts`/candles.
- Browser DOM rendering in `apps/web`, especially news `content_html`, headlines, URLs, explanations JSON.
- Electron `shell.openExternal` and `BrowserWindow.loadURL`.
- `Bun.spawn` in Databento/IBKR adapters and deployment scripts invoking shell/ssh/docker.
- Logs/metrics containing URLs, provider errors, trace IDs, possibly secrets if not redacted.
## Framework Contracts and Hidden Control Channels
- **Bun server routing**: `services/api/src/index.ts` uses manual `if` routing. Path normalization, percent-decoding, and regex routes (`/flow/packets/:id`, `/flow/alerts/:trace/context`) are security-sensitive.
- **Next.js route handlers**: `apps/web/app/api/admin/synthetic/**` are forced dynamic and proxy to the API. Security depends on feature env and server-side `SYNTHETIC_ADMIN_TOKEN`; `NEXT_PUBLIC_API_URL` is a hidden control channel for target API base.
- **Next.js public env**: variables prefixed `NEXT_PUBLIC_*` are exposed to clients. Do not place secrets there. `NEXT_PUBLIC_API_URL` controls browser/API reachability and admin proxy target base in server code.
- **Proxy/bind assumptions**: Compose defaults `WEB_BIND_IP` and `API_BIND_IP` to `127.0.0.1`; external access likely via reverse proxy on `npm-shared`. If overridden to `0.0.0.0`, unauthenticated API/WS become directly reachable.
- **Internal services unauthenticated by default**: NATS, ClickHouse, Redis compose definitions do not show credentials/TLS. The Docker network is an implicit trust boundary.
- **Header contracts**: Synthetic admin uses `Authorization: Bearer`; no other route-level auth headers observed. If a reverse proxy injects auth headers, handlers do not re-check them.
- **WebSocket contracts**: Bun `server.upgrade` accepts based on path only; no Origin/auth check observed. `/ws/live` message schema is the main control.
- **Runtime modes**: Synthetic/admin behavior depends on `SYNTHETIC_CONTROL_ENABLED`, `SYNTHETIC_ADMIN_TOKEN`, `NEXT_PUBLIC_SYNTHETIC_ADMIN`, adapter envs. API deliver policy and consumer reset affect stream replay behavior.
- **Electron contracts**: Trust is origin-based (`flow.deltaisland.io`, `127.0.0.1:3000`, `localhost:3000`); sandbox/contextIsolation/webSecurity are enabled; permission prompts denied; external URLs opened only when source is trusted.
- **Storage escaping contract**: ClickHouse string safety depends on local `quoteString`, `buildStringList`, `clamp*`, and typed table constants. Any future query builder bypassing these helpers is high risk.
## Threat Model
### Assets
- Alpaca/Databento/IBKR API credentials and NATS/ClickHouse/Redis URLs.
- Market/news data and derived smart-money alerts/flow packets (proprietary research value).
- Integrity of event stream, replay history, and classifier outputs.
- Availability of live API, WS fanout, NATS JetStream, ClickHouse, Redis.
- Admin synthetic-control state.
- Desktop user environment (external URL opening/browser trust).
- Deployment secrets and CI credentials.
### Threat actors
- Anonymous internet clients if web/API are exposed through reverse proxy or bind-IP override.
- Malicious/compromised market data provider, websocket MITM where TLS/config is weakened, or malformed feed data.
- Network peer/container on Docker shared/default networks.
- Operator/local attacker who can modify env vars or Python binary paths.
- Malicious webpage/content rendered in news/web UI, or compromised trusted origin in Electron.
- Supply-chain attacker via npm/Bun/Python dependencies or CI workflow changes.
### Abuse paths and priorities
| Threat | Boundary | Impact | Likelihood | Priority | Existing controls | Review focus |
|---|---|---:|---:|---:|---|---|
| Unauthenticated REST/WS data extraction or scraping | Internet -> API | Med/High | Med if exposed | High | Bind defaults to localhost | Confirm intended auth; add API auth/rate limits/Origin checks |
| Synthetic admin token bypass/leak/misproxy | Browser/Next -> API admin | Med | Med | High | Bearer token, feature flag | Verify `authenticateSyntheticAdminRequest`, proxy URL allowlist, no token in client bundle/logs |
| ClickHouse injection or expensive query DoS | HTTP params -> storage | High | Med | High | zod, clamp, `quoteString` | Custom SAST for string SQL helpers and unbounded ranges |
| Poisoned feed data corrupts analytics/UI | Provider -> ingest -> NATS/UI | High integrity | Med | High | schemas, field parsing | Validate schemas, size limits, HTML sanitization, anomaly handling |
| NATS/Redis/ClickHouse lateral abuse from network peer | Docker/shared network -> infra | High | Low/Med | High | localhost port binds for web/API only | Add service credentials/TLS/ACLs; network isolation |
| WebSocket resource exhaustion | Internet -> API WS | Med/High availability | Med | High | schema parse for live messages | Connection/message limits, heartbeat, per-IP quotas |
| Electron navigation/openExternal abuse | Web content -> desktop shell | High local user impact | Low/Med | Medium | origin allowlist, sandbox, no nodeIntegration | Verify external URL schemes, downloads, CSP |
| XSS via news/content or explanation rendering | Feed/API -> web DOM | High if same origin admin token/proxy | Med | High | news summary escaping fallback | Audit `dangerouslySetInnerHTML`, URL rendering, CSP |
| Child-process command/path misuse | Env -> Bun.spawn Python | Med/High | Low/Med | Medium | args array, script path constant | Validate `pythonBin`, avoid shell, handle stdout size |
| CI/deploy secret leakage or command injection | PR/env -> scripts/workflows | High | Low/Med | Medium | limited visible workflows | Audit deploy scripts and Forgejo workflow triggers |
### Recommended controls for later phases
- Treat API/WS as public unless proven behind authenticated reverse proxy; require handler-level auth for non-public data and admin controls.
- Add Origin/token checks and connection/message rate limits to WS endpoints.
- Centralize ClickHouse query construction; prefer parameterized ClickHouse client support if available.
- Sanitize or strip provider HTML before storage/rendering; add CSP in Next app.
- Add NATS/Redis/ClickHouse credentials/ACLs/TLS or restrict network access; do not rely on Docker network trust.
- Harden admin proxy with strict API base allowlist and server-only env names for secrets.
## Domain Attack Research
Identified domains: HTTP/Next.js, WebSocket, Electron, NATS/JetStream message bus, ClickHouse SQL/query construction, Redis cache, external market-data ingestion/parsing (JSON/msgpack), subprocess execution, Docker/deployment/CI, browser rendering/XSS. Mode B applies (security-sensitive dependencies as consumers). Mode C applies (HTTP/WS, SQL, Redis, message queues, Electron, parsing, subprocess, containers/CI). Mode A is not primary because Islandflow is not distributed as a public library/protocol, though internal package API sharp edges matter.
### Domain: HTTP API / Next.js / Bun routing
**Identified via:** `services/api` manual HTTP routing, `apps/web` Next.js app and route handlers, Next advisory history.
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| Auth bypass / missing handler auth | Public routes unintentionally expose data/control | Find route handlers without auth checks; diff public route inventory | High |
| Path/matcher confusion | Encoded paths/trailing slashes bypass manual checks/proxy rules | Test encoded path variants and reverse proxy rewrites | Med |
| SSRF/open proxy via admin proxy | Server fetches attacker-controlled base/path | Track `new URL(path, NEXT_PUBLIC_API_URL)` and env controls | Med |
| Cache poisoning | Host/forwarded headers or Next caching leak dynamic data | Review caching headers, `dynamic`, reverse proxy config | Low/Med |
Custom SAST targets: route handlers in `services/api/src/index.ts` and `apps/web/app/api/**` lacking auth; `fetch(new URL(... env ...))`; use of `req.headers`/`Host`/`X-Forwarded-*`; public route changes. Manual checklist: confirm intended public endpoints; fuzz paths; enforce auth and rate limits. Research sources: advisory summary, wooyun-legacy web methodology, last30days/web-search class knowledge.
### Domain: WebSocket
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| Unauthenticated data streaming | Any client subscribes to feed/alerts | Enumerate `/ws/*` upgrades without auth/origin checks | High |
| Resource exhaustion | Many connections/messages or huge frames | Look for max payload, conn limits, heartbeat | High |
| Subscription filter abuse | Malformed filters cause broad fanout or CPU use | Validate `LiveClientMessageSchema`, filter matching paths | Med |
Custom SAST: `serverRef.upgrade`, `websocket.message`, `JSON.parse`, zod parse error loops, broadcast loops. Manual: origin/auth tests; slow-client behavior; payload size tests.
### Domain: ClickHouse SQL / query construction
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| SQL injection | Manual string interpolation misses escaping | Taint HTTP params to `client.query({query})`; require `quoteString/clamp*` | High |
| Query DoS | wide time ranges/high cardinality IN/LIKE/position | Find unbounded arrays/ranges and expensive predicates | High |
| Data exfiltration | unauth history/replay endpoints dump proprietary data | Route inventory + auth absence | High |
Custom SAST: RemoteFlowSource query params/body -> `query:` template literals in `packages/storage`; array length to `IN`/OR predicates; limits > configured max. Manual: test quotes/unicode/null bytes; verify max IDs and ranges.
### Domain: NATS/JetStream message bus
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| Subject spoofing | Network peer publishes fake market/admin events | Review connect options, credentials, subject ACLs | High |
| Replay/consumer confusion | Durable policy reset replays stale data as live | Trace `API_DELIVER_POLICY`, replay service controls | Med |
| KV control tampering | Synthetic control state modified by unauthorized peer | Review KV bucket ACL and admin endpoints | High |
Custom SAST: `publishJson`, `subscribeJson`, `writeSyntheticControlState`, unvalidated payloads. Manual: verify NATS auth/TLS in prod, subject permissions, event schemas.
### Domain: External feed parsing (JSON/msgpack/news HTML)
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| Parser/resource DoS | Large JSON/msgpack/websocket frames exhaust memory/CPU | Locate decode/JSON.parse without size/time bounds | High |
| Schema confusion | Partial provider payload becomes valid incorrect event | Compare zod schemas and adapter field defaults | Med |
| Stored XSS via news HTML | Provider `content` stored/rendered as HTML | Trace `content_html` to React render sinks | High |
Custom SAST: `decode`, `JSON.parse`, `new TextDecoder`, `content_html`, `dangerouslySetInnerHTML`, URLs. Manual: malformed provider fixtures; max message sizes; sanitize HTML.
### Domain: Electron desktop
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| Navigation escape | Untrusted page loaded in privileged shell | Check `loadURL`, origin allowlists, redirects | Med |
| openExternal abuse | Custom schemes/file URLs launched | Verify only http/https external URLs | Med |
| Node integration/IPC abuse | Web content gains local code exec | Check BrowserWindow preferences/preload/IPC | Low currently |
Custom SAST: `shell.openExternal`, `loadURL`, `setWindowOpenHandler`, `will-navigate`, BrowserWindow prefs. Manual: redirect chains, punycode/origin tests, CSP/download handling.
### Domain: Redis/cache
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| Cache poisoning | Malicious internal publisher/data seeds hot live state | Trace key construction and schema validation | Med |
| Availability DoS | huge values/keys or no TTL memory growth | Review `set`/`lpush`/TTL use | Med |
| Unauthorized access | Redis default no password in compose | Deployment config review | High internal |
Custom SAST: Redis key builders with attacker input, missing TTL, `JSON.parse` of cache values.
### Domain: Subprocess / Python sidecars
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| Command injection/path hijack | Env-controlled binary/args execute attacker program | Ensure no shell; validate `pythonBin`; constant script paths | Med |
| stdout parsing DoS | Child emits unbounded line/JSON | Limit line length and restart loops | Med |
| Secret leakage | API keys in args/env/logs | Review spawned args and stderr logging | Low/Med |
Custom SAST: `Bun.spawn`, env-derived args, `stderr: inherit`, readLines buffer growth.
### Domain: Docker/deployment/CI supply chain
| Attack | Description | Detection strategy | Relevance |
|---|---|---|---|
| Insecure bind/exposure | API/NATS/ClickHouse/Redis reachable publicly | Parse compose ports/networks/env overrides | High |
| Secret leakage in deploy scripts | Tokens printed or sent to PR contexts | Review workflow triggers/scripts | Med |
| Dependency takeover/CVE | npm/Python base images/deps vulnerable | Dependency and image scanning | Med |
Custom SAST: workflows with untrusted PR + secrets, deploy scripts shell interpolation, Docker `ports` to `0.0.0.0`, no auth configs.
## Phase 4 CodeQL Extraction Targets
| Slice | Source type | Source | Sink kind | Sink |
|---|---|---|---|---|
| DFD-1 API params -> ClickHouse | RemoteFlowSource | URL search params/path/body in `services/api/src/index.ts` | sql-execution | `client.query({ query })` in `packages/storage/src/clickhouse.ts` |
| DFD-2 WS messages -> subscriptions/fanout | RemoteFlowSource | WebSocket `message`, path upgrade | deserialization / resource exhaustion | `LiveClientMessageSchema.parse`, JSON parse, broadcast/send loops |
| DFD-3 feeds -> NATS/storage/UI | RemoteFlowSource | WebSocket/REST provider messages, child stdout | deserialization / code/data injection | `JSON.parse`, msgpack `decode`, `publishJson`, `content_html` render sinks |
| DFD-4 admin proxy/control | RemoteFlowSource + EnvironmentVariable | Next request body; `NEXT_PUBLIC_API_URL`, `SYNTHETIC_ADMIN_TOKEN` | http-request / authz decision | `fetch(url.toString())`, `writeSyntheticControlState` |
| DFD-5 Electron navigation | EnvironmentVariable + RemoteFlowSource | `ISLANDFLOW_DESKTOP_START_URL`, page navigation/window.open URL | http-request / code-execution-adjacent | `BrowserWindow.loadURL`, `shell.openExternal` |
| Python sidecars | EnvironmentVariable | `DATABENTO_PYTHON_BIN`/`IBKR_*` env args | command-execution | `Bun.spawn` |
| Redis live state | RemoteFlowSource | NATS events, API filters | cache/data poisoning | Redis client methods, JSON cache serialization |
## Spec Gap Candidates
No formal RFC/spec commitments are declared. De facto contracts to check in Phase 9:
- HTTP/1.1 and WebSocket behavior (Bun server, `ws` clients).
- OCC option symbol parsing and market-data provider contracts (Alpaca, Databento, IBKR).
- NATS/JetStream subject and durable consumer semantics.
- ClickHouse SQL escaping/string literal semantics.
- Electron security model for sandbox/context isolation/navigation.
## Coverage Gaps
- Production reverse proxy configuration is not present; API exposure/auth assumptions must be validated from deployment host.
- Full `services/api/src/index.ts` is large; later phases should extract route inventory mechanically and test every route.
- UI rendering sinks (`apps/web/app/**`) require deeper review for `dangerouslySetInnerHTML`, external links, and CSP.
- NATS/ClickHouse/Redis production credentials/TLS/ACLs are not visible in compose; if configured outside repo, collect them.
- Rate limiting is not apparent for REST/WS; availability risk remains unquantified.
- CI canonical path in README references `.forgejo/workflows`, while `.github/workflows` also exists; audit both.
- Domain research used repository/advisory evidence and built-in playbook knowledge; live web/MCP research was not available in this runtime.
## Static Analysis Summary
Stage 04 prioritized `piolium/attack-surface/candidates-summary.md` and `candidates.jsonl`, especially high-score hidden-control-channel, WebSocket, SQL/query, SSRF, and unsafe HTML candidates. `codeql` and `semgrep` were checked before scanning but were unavailable on PATH, so the run used the required fallback (`grep` + `read`) rather than fabricated scan results. Semgrep Pro could not be executed because the CLI was missing; the fallback reason is documented here, and transient `piolium/semgrep-res/` was removed during cleanup.
Artifacts produced:
- `piolium/attack-surface/source-sink-flows-all-severities.md`
- Structural fallback JSON/SARIF under `piolium/codeql-artifacts/`
- Custom placeholders/rules under `piolium/codeql-queries/` and `piolium/semgrep-rules/`
- Draft findings: `p4-001`, `p4-002`, `p4-003` (cap 30 respected)
Built-in CodeQL suites run: none (`codeql` unavailable). Built-in Semgrep rulesets run: none (`semgrep` unavailable). Custom Semgrep rule file was authored but not executed by Semgrep; manual grep/read validation matched the risky instances.
## CodeQL Structural Analysis
CodeQL database build/extraction was skipped because the `codeql` binary was not installed on PATH. Fallback structural extraction still populated the mandatory files for downstream phases:
- Entry points: 7 (`piolium/codeql-artifacts/entry-points.json`)
- Sinks: 8 (`piolium/codeql-artifacts/sinks.json`)
- Reachable slices: 5 of 7 (`piolium/codeql-artifacts/call-graph-slices.json`)
### Machine-Generated DFD Diagram
```mermaid
flowchart LR
A[HTTP req/query params] --> B[services/api routes]
B --> C[ClickHouse query sinks]
W[WS upgrade/message] --> X[JSON.parse + Zod]
X --> Y[live subscriptions/socket.send]
N[Provider news content_html] --> S[regex sanitizeNewsHtml]
S --> H[dangerouslySetInnerHTML]
P[Next admin proxy routes/env] --> F[fetch API base]
E[Env Python bin/args] --> R[Bun.spawn]
D[Electron navigation] -. no path in fallback .-> Z[loadURL/openExternal]
```
### Machine-Generated CFD Diagram
```mermaid
flowchart TD
Q[Request arrives] --> R{Admin route?}
R -- yes --> T{Synthetic enabled + token matches?}
T -- pass --> U[writeSyntheticControlState]
T -- fail --> V[401/404/409]
R -- no/data route --> K[No app auth]
K --> L[ClickHouse fetch JSON]
W[WS upgrade] --> O{Origin/auth checked?}
O -- no --> P[Accept socket/fanout]
N[News HTML] --> G{Regex sanitizer passes?}
G -- yes --> H[Render HTML]
```
Notable entry points not fully represented in Phase 3 DFD slices: client-side `window.location.host` API/WS selection and response `content-type` robustness checks. Notable sinks mapping to high-risk flows: `dangerouslySetInnerHTML`, WebSocket `socket.send`, and ClickHouse `client.query`.
## SAST Enrichment
| Finding | Classification | Attacker Control | Boundary | CodeQL Reachability | Verdict |
|---------|---------------|-----------------|----------|-------------------|---------|
| p4-001 stored-xss-news-html-regex-sanitizer | security | upstream news provider / bus publisher controls `content_html` | external feed -> browser DOM | reachable (fallback slice DFD-3) | keep |
| p4-002 unauthenticated-websocket-market-data-streams | security | remote client controls WS upgrade/messages | internet/proxy -> API live streams | reachable (fallback slice DFD-2) | keep |
| p4-003 public-api-exposes-queryable-market-history | security | remote client controls HTTP params if API exposed | internet/proxy -> ClickHouse-backed data API | reachable (fallback slice DFD-1) | keep |
| admin-proxy-env-base-url-fetch | env/tooling/admin-only | deployment env controls `NEXT_PUBLIC_API_URL`; route path fixed | server env -> outbound fetch | reachable (fallback slice DFD-4) | drop as draft; monitor config |
| Python sidecar Bun.spawn | env/tooling/admin-only | env/config controls python binary/args | local service config -> subprocess | reachable (fallback Python sidecars) | drop |
| test secret literals | correctness/env | source-controlled tests | none | no-slice | drop |
| static redirects | correctness | no user-controlled URL | none | no-slice | drop |
## Spec Gap Analysis
### Gap: Root Docker Compose publishes unauthenticated ClickHouse, Redis, and NATS control planes
- **Contract**: Docker deployment/internal-service contract for infrastructure dependencies (ClickHouse, Redis, NATS/JetStream) should keep data/control planes internal unless credentials/TLS/ACLs are configured.
- **Security Assumption**: Application services treat ClickHouse, Redis, and NATS as trusted internal dependencies; API-layer validation/auth is not re-applied to direct database, cache, or message-bus clients.
- **Code Path**: `docker-compose.yml:1` — root compose publishes infrastructure ports; `deployment/docker/docker-compose.yml:120` — production compose keeps those services internal-only by omitting host `ports`.
- **Gap Type**: framework-contract | hidden-control-channel | proxy-trust | runtime-mode
- **Attack Vector**: A network attacker reaches the host-published service ports, publishes forged NATS messages, tampers with Redis state, or queries/modifies ClickHouse directly.
- **Exploit Conditions**: Root compose is used on a network-reachable host and host firewall does not block `8123`, `9000`, `6379`, `4222`, or `8222`.
- **Impact**: Data confidentiality/integrity compromise and bypass of API-layer controls for market history, live state, and event streams.
- **Severity**: HIGH
- **Evidence**: Root compose maps `8123:8123`, `9000:9000`, `6379:6379`, `4222:4222`, and `8222:8222`; production compose defines the same services without host `ports`.
## Authorization Audit
- Public routes matrix: `piolium/attack-surface/public-routes-authz-matrix.md`
- Public/network operations reviewed: 17 matrix rows covering API REST groups, API WebSocket groups, Next public pages, and Next synthetic-admin proxy routes.
- Frameworks covered: Bun manual routing/WebSocket upgrade, Next.js route handlers/file routes.
- Middleware/proxy-derived identity reviewed: backend synthetic bearer token, `x-synthetic-admin-token`, Next admin proxy token injection, bind/reverse-proxy exposure assumptions, WebSocket path-only upgrades.
- Drafts filed: 1 (`authz-missing-guard`): `piolium/findings-draft/p5-001-public-next-admin-proxy-confers-synthetic-admin.md`.
- Remaining review targets: unauthenticated market-data REST/history/replay/WebSocket surfaces are currently treated as intended-public/read-only, but should be chamber-reviewed against product policy because exposure depends on reverse proxy/bind settings and data may have proprietary value.
## State & Concurrency Audit
- State-holding entities catalogued: 8
- Concurrency primitives observed: JetStream manual ack/explicit ack; NATS KV for synthetic control. No language locks, DB transactions, SELECT FOR UPDATE, advisory locks, or Redis/distributed locks observed.
- Idempotency infrastructure: partial/in-memory only (`recentStructureEmits`, live/UI dedupe); no durable processed-event/idempotency store for JetStream consumers.
- Drafts filed: 2 (idempotency: 1, stale-read: 1)
## Cross-Service Taint Propagation
- Services analysed: 8
- Edges stitched: 15 (1 http, 0 grpc, 13 queue, 1 db-write, 0 file)
- Coverage gaps: provider-only HTTP calls excluded; raw `options.prints` has no in-repo consumer identified; NATS subject identity depends on deployment controls — see `piolium/attack-surface/cross-service-edges.md`
- Drafts filed: 1 (`queue-source-auth`: 1)

View file

@ -0,0 +1,64 @@
# Lite Recon — Q0
Generated by piolium at 2026-05-27T05:18:10.214Z
## Target
- Path: `/Users/kell/dev/islandflow`
- Repository: (unknown)
- Total files (scanned): 291
- Total bytes (scanned): 3.5 MB
## Git
- Commit: ffbdbc337638004be49775c85a2f0b10b7e55563
- Branch: security-audit
- History available: true
Recent commits:
```
ffbdbc3 docs: add May 24 standup git summary
3300728 set up forgejo ci baseline
3c444b7 Merge pull request 'rename tape to options and replace web rail with overlay drawer' (#11) from sidebar-redesign into main
7ca0e05 rename tape to options and switch the web shell to a drawer
f056f6d clarify when turn docs are actually required
fda7d5f add turn doc for pierre diffs policy update
4a0e9e7 default turn-doc diffs to @pierre/diffs and add dependency
5ff2fa6 turn doc instruction tuning
2e48283 sync github mirror for docs pages workflow fix
aae3fa1 fix docs pages workflow for gh-pages branch deploy
```
## Languages
- TypeScript: 134 file(s)
- Shell: 11 file(s)
- Python: 2 file(s)
## Build / Project Manifests
- `apps/desktop/package.json`
- `apps/web/package.json`
- `deployment/docker/Dockerfile.ingest-options`
- `deployment/docker/Dockerfile.service`
- `deployment/docker/Dockerfile.web`
- `deployment/docker/docker-compose.yml`
- `deployment/docker/workspace-root/package.json`
- `docker-compose.yml`
- `package.json`
- `packages/bus/package.json`
- `packages/config/package.json`
- `packages/observability/package.json`
- `packages/storage/package.json`
- `packages/types/package.json`
- `services/api/package.json`
- `services/candles/package.json`
- `services/compute/package.json`
- `services/eod-enricher/package.json`
- `services/ingest-equities/package.json`
- `services/ingest-news/package.json`
- `services/ingest-options/package.json`
- `services/ingest-options/py/requirements.txt`
- `services/refdata/package.json`
- `services/replay/package.json`

View file

@ -0,0 +1,40 @@
# Manual Attack Surface Inventory (Stage 08)
## Highest-impact slices selected
1. Synthetic admin control: public Next.js route handlers proxy to API admin endpoints with server bearer token.
2. Provider/news HTML to browser DOM: Alpaca `content` is stored and later rendered through a regex sanitizer and `dangerouslySetInnerHTML`.
3. Live WebSocket/API market data exposure: public WS upgrades and history reads have no handler-level auth/origin checks.
4. Root Docker Compose infrastructure: ClickHouse, Redis, and NATS are published on host ports without credentials in the compose file.
## Public routes / URLs
- Next admin proxy: `GET /api/admin/synthetic/status`, `GET/PUT /api/admin/synthetic/control` (`apps/web/app/api/admin/synthetic/status/route.ts:5-7`, `apps/web/app/api/admin/synthetic/control/route.ts:5-17`).
- API admin backend: `GET /admin/synthetic/status`, `GET/PUT /admin/synthetic/control` (`services/api/src/index.ts:1364-1388`).
- API history/news and related reads: `/history/news` (`services/api/src/index.ts:1656-1660`) plus other unauthenticated history/replay/read endpoints documented in P5 matrix.
- WebSockets: `/ws/options`, `/ws/options-nbbo`, `/ws/equities`, `/ws/equity-candles`, `/ws/equity-quotes`, `/ws/equity-joins`, `/ws/inferred-dark`, `/ws/flow`, `/ws/classifier-hits`, `/ws/smart-money`, `/ws/alerts`, `/ws/live` (`services/api/src/index.ts:1846-1936`).
- Host infra ports from root compose: ClickHouse HTTP/native `8123/9000`, Redis `6379`, NATS client/monitor `4222/8222` (`docker-compose.yml:4-24`).
## Attacker-controlled sources
- Anonymous browser requests to Next route handlers when `NEXT_PUBLIC_SYNTHETIC_ADMIN=1`.
- HTTP query/path parameters and WebSocket connection/message bytes to the API.
- Alpaca/provider news `item.content`, `item.summary`, `item.url`, and symbols before persistence/display.
- Network clients reaching published compose ports on the host.
- Environment hidden controls: `NEXT_PUBLIC_API_URL`, `SYNTHETIC_ADMIN_TOKEN`, `API_HOST`, compose deployment choice.
## Sinks
- NATS KV write of synthetic control state through API admin PUT (`services/api/src/index.ts:1386-1388`).
- Browser DOM HTML sink: `dangerouslySetInnerHTML` for news story body (`apps/web/app/terminal.tsx:5009`).
- WebSocket `serverRef.upgrade` and live snapshots (`services/api/src/index.ts:1847-1935`, `1982-2008`).
- ClickHouse query reads for history/replay (`services/api/src/index.ts:1556-1660`, storage package).
- Direct ClickHouse/Redis/NATS network services from root compose (`docker-compose.yml:4-24`).
## Hidden control channels
- `NEXT_PUBLIC_SYNTHETIC_ADMIN` enables/disables admin proxy; `NEXT_PUBLIC_API_URL` chooses the privileged proxy target; `SYNTHETIC_ADMIN_TOKEN` is injected server-side (`apps/web/app/api/admin/synthetic/shared.ts:10-22`, `44-55`).
- API admin accepts either bearer token or `x-synthetic-admin-token` fallback (`services/api/src/index.ts:320-333`).
- API exposure depends on `API_HOST`/reverse proxy rather than handler auth; WS routes do not inspect `Origin`.
- Root compose vs production compose changes infra from internal-only to host-published.
## Exploit-relevant paths
- Browser -> Next `/api/admin/synthetic/control` -> server injects bearer -> API admin -> NATS KV synthetic control mutation.
- Provider news HTML -> `content_html` -> ClickHouse/API `/history/news` -> React drawer -> regex sanitizer -> `dangerouslySetInnerHTML`.
- Remote WS client -> `/ws/live` upgrade -> subscribe message -> `liveState.getSnapshot` -> live/research data stream.
- Network client -> host port `4222` NATS -> publish forged subjects / KV updates; or `8123/9000` ClickHouse -> query/alter data; or `6379` Redis -> read/write cache.

View file

@ -0,0 +1,18 @@
@clickhouse/client
@electron-forge/cli
@electron-forge/core
@electron-forge/maker-zip
@msgpack/msgpack
@pierre/diffs
@tanstack/react-virtual
@types/node
electron
lightweight-charts
nats
next
react
react-dom
redis
typescript
ws
zod

View file

@ -0,0 +1 @@
{"resultsPerPage":0,"startIndex":0,"totalResults":0,"format":"NVD_CVE","version":"2.0","timestamp":"2026-05-27T05:19:20.553","vulnerabilities":[]}

View file

@ -0,0 +1,116 @@
electron GHSA-2q4g-w47c-4674
electron GHSA-3c8v-cfp5-9885
electron GHSA-3p22-ghq8-v749
electron GHSA-4p4r-m79c-wq3v
electron GHSA-4w88-rjj3-x7wp
electron GHSA-532v-xpq5-8h95
electron GHSA-56pc-6jqp-xqj8
electron GHSA-5rqw-r77c-jp79
electron GHSA-6h98-cf9g-vmg2
electron GHSA-6r2x-8pq8-9489
electron GHSA-6vrv-94jv-crrg
electron GHSA-77xc-hjv8-ww97
electron GHSA-7fv9-m79r-j9x8
electron GHSA-7m48-wc93-9g85
electron GHSA-7x97-j373-85x5
electron GHSA-8337-3p73-46f4
electron GHSA-8x5q-pvf5-64mp
electron GHSA-8xwg-wv7v-4vqp
electron GHSA-9899-m83m-qhpj
electron GHSA-995f-9x5r-2rcj
electron GHSA-9w97-2464-8783
electron GHSA-9wfr-w7mm-pc7f
electron GHSA-f37v-82c4-4x64
electron GHSA-f3pv-wv63-48x8
electron GHSA-f9mq-jph6-9mhm
electron GHSA-fjqr-fx3f-g4rv
electron GHSA-gvcj-pfq2-wxj7
electron GHSA-gxh7-wv9q-fwfr
electron GHSA-h9jc-284h-533g
electron GHSA-hv9c-qwqg-qj3v
electron GHSA-hvf8-h2qh-37m9
electron GHSA-j7hp-h8jx-5ppr
electron GHSA-jfqg-hf23-qpw2
electron GHSA-jfqx-fxh3-c62j
electron GHSA-jjp3-mq3x-295m
electron GHSA-m93v-9qjc-3g79
electron GHSA-mpjm-v997-c4h4
electron GHSA-mq8j-3h7h-p8g7
electron GHSA-mwmh-mq4g-g6gr
electron GHSA-p2jh-44qj-pf2v
electron GHSA-p7v2-p9m8-qqg7
electron GHSA-qqvq-6xgj-jw8g
electron GHSA-r5p7-gp4j-qhrx
electron GHSA-vmqv-hx8q-j7mg
electron GHSA-w222-53c6-c86p
electron GHSA-xj5x-m3f3-5x3h
electron GHSA-xw5q-g62x-2qjc
electron GHSA-xwr5-m59h-vwqr
nats GHSA-82rf-q3pr-4f6p
nats GHSA-prmc-5v5w-c465
next GHSA-223j-4rm8-mrmf
next GHSA-25mp-g6fv-mqxx
next GHSA-267c-6grr-h53f
next GHSA-26hh-7cqf-hhc6
next GHSA-36qx-fr4f-26g5
next GHSA-3f5c-4qxj-vmpf
next GHSA-3g8h-86w9-wvmq
next GHSA-3h52-269p-cp9r
next GHSA-3x4c-7xq6-9pq8
next GHSA-4342-x723-ch2f
next GHSA-492v-c6pp-mqqv
next GHSA-5f7q-jpqc-wp7h
next GHSA-5j59-xgg2-r9c4
next GHSA-5vj8-3v2h-h38v
next GHSA-67rr-84xm-4c7r
next GHSA-77r5-gw3j-2mpf
next GHSA-7gfc-8cq8-jh5f
next GHSA-7m27-7ghc-44w9
next GHSA-8h8q-6873-q5fj
next GHSA-9g9p-9gw9-jx7f
next GHSA-9gr3-7897-pp7m
next GHSA-9qr9-h5gf-34mp
next GHSA-c4j6-fc7j-m34r
next GHSA-c59h-r6p8-q9wc
next GHSA-f82v-jwr5-mffw
next GHSA-ffhc-5mcf-pf4q
next GHSA-fmvm-x8mv-47mj
next GHSA-fq54-2j52-jc42
next GHSA-fq77-7p7r-83rj
next GHSA-fr5h-rqp8-mj6g
next GHSA-g5qg-72qw-gw5v
next GHSA-g77x-44xx-532m
next GHSA-ggv3-7p47-pfv8
next GHSA-gp8f-8m3g-qvj9
next GHSA-gx5p-jg67-6x7h
next GHSA-h25m-26qc-wcjf
next GHSA-h27x-g6w4-24gq
next GHSA-h64f-5h5j-jqjh
next GHSA-jcc7-9wpm-mj36
next GHSA-m34x-wgrh-g897
next GHSA-mg66-mrh9-m8jx
next GHSA-mq59-m269-xvcx
next GHSA-mwv6-3258-q52c
next GHSA-q4gf-8mx6-v5v3
next GHSA-qpjv-v59x-3qc4
next GHSA-qw96-mm2g-c8m7
next GHSA-r2fc-ccr8-96c4
next GHSA-vfv6-92ff-j949
next GHSA-vxf5-wxwp-m7g9
next GHSA-w37m-7fhw-fmv9
next GHSA-wfc6-r584-vfw7
next GHSA-wff4-fpwg-qqv3
next GHSA-wr66-vrwm-5g5x
next GHSA-x56p-c8cg-q435
next GHSA-xv57-4mr9-wg8v
react GHSA-g53w-52xc-2j85
react GHSA-hg79-j56m-fxgv
react-dom GHSA-mvjj-gqq2-p4hw
redis GHSA-35q2-47q7-3pc3
ws GHSA-2mhh-w6q8-5hxw
ws GHSA-3h5v-q93c-6h6q
ws GHSA-58qx-3vcg-4xpx
ws GHSA-5v72-xg48-5rpm
ws GHSA-6663-c963-2gqg
ws GHSA-6fc8-4gx4-v693
zod GHSA-m95q-7qp3-xv42
1 electron GHSA-2q4g-w47c-4674
2 electron GHSA-3c8v-cfp5-9885
3 electron GHSA-3p22-ghq8-v749
4 electron GHSA-4p4r-m79c-wq3v
5 electron GHSA-4w88-rjj3-x7wp
6 electron GHSA-532v-xpq5-8h95
7 electron GHSA-56pc-6jqp-xqj8
8 electron GHSA-5rqw-r77c-jp79
9 electron GHSA-6h98-cf9g-vmg2
10 electron GHSA-6r2x-8pq8-9489
11 electron GHSA-6vrv-94jv-crrg
12 electron GHSA-77xc-hjv8-ww97
13 electron GHSA-7fv9-m79r-j9x8
14 electron GHSA-7m48-wc93-9g85
15 electron GHSA-7x97-j373-85x5
16 electron GHSA-8337-3p73-46f4
17 electron GHSA-8x5q-pvf5-64mp
18 electron GHSA-8xwg-wv7v-4vqp
19 electron GHSA-9899-m83m-qhpj
20 electron GHSA-995f-9x5r-2rcj
21 electron GHSA-9w97-2464-8783
22 electron GHSA-9wfr-w7mm-pc7f
23 electron GHSA-f37v-82c4-4x64
24 electron GHSA-f3pv-wv63-48x8
25 electron GHSA-f9mq-jph6-9mhm
26 electron GHSA-fjqr-fx3f-g4rv
27 electron GHSA-gvcj-pfq2-wxj7
28 electron GHSA-gxh7-wv9q-fwfr
29 electron GHSA-h9jc-284h-533g
30 electron GHSA-hv9c-qwqg-qj3v
31 electron GHSA-hvf8-h2qh-37m9
32 electron GHSA-j7hp-h8jx-5ppr
33 electron GHSA-jfqg-hf23-qpw2
34 electron GHSA-jfqx-fxh3-c62j
35 electron GHSA-jjp3-mq3x-295m
36 electron GHSA-m93v-9qjc-3g79
37 electron GHSA-mpjm-v997-c4h4
38 electron GHSA-mq8j-3h7h-p8g7
39 electron GHSA-mwmh-mq4g-g6gr
40 electron GHSA-p2jh-44qj-pf2v
41 electron GHSA-p7v2-p9m8-qqg7
42 electron GHSA-qqvq-6xgj-jw8g
43 electron GHSA-r5p7-gp4j-qhrx
44 electron GHSA-vmqv-hx8q-j7mg
45 electron GHSA-w222-53c6-c86p
46 electron GHSA-xj5x-m3f3-5x3h
47 electron GHSA-xw5q-g62x-2qjc
48 electron GHSA-xwr5-m59h-vwqr
49 nats GHSA-82rf-q3pr-4f6p
50 nats GHSA-prmc-5v5w-c465
51 next GHSA-223j-4rm8-mrmf
52 next GHSA-25mp-g6fv-mqxx
53 next GHSA-267c-6grr-h53f
54 next GHSA-26hh-7cqf-hhc6
55 next GHSA-36qx-fr4f-26g5
56 next GHSA-3f5c-4qxj-vmpf
57 next GHSA-3g8h-86w9-wvmq
58 next GHSA-3h52-269p-cp9r
59 next GHSA-3x4c-7xq6-9pq8
60 next GHSA-4342-x723-ch2f
61 next GHSA-492v-c6pp-mqqv
62 next GHSA-5f7q-jpqc-wp7h
63 next GHSA-5j59-xgg2-r9c4
64 next GHSA-5vj8-3v2h-h38v
65 next GHSA-67rr-84xm-4c7r
66 next GHSA-77r5-gw3j-2mpf
67 next GHSA-7gfc-8cq8-jh5f
68 next GHSA-7m27-7ghc-44w9
69 next GHSA-8h8q-6873-q5fj
70 next GHSA-9g9p-9gw9-jx7f
71 next GHSA-9gr3-7897-pp7m
72 next GHSA-9qr9-h5gf-34mp
73 next GHSA-c4j6-fc7j-m34r
74 next GHSA-c59h-r6p8-q9wc
75 next GHSA-f82v-jwr5-mffw
76 next GHSA-ffhc-5mcf-pf4q
77 next GHSA-fmvm-x8mv-47mj
78 next GHSA-fq54-2j52-jc42
79 next GHSA-fq77-7p7r-83rj
80 next GHSA-fr5h-rqp8-mj6g
81 next GHSA-g5qg-72qw-gw5v
82 next GHSA-g77x-44xx-532m
83 next GHSA-ggv3-7p47-pfv8
84 next GHSA-gp8f-8m3g-qvj9
85 next GHSA-gx5p-jg67-6x7h
86 next GHSA-h25m-26qc-wcjf
87 next GHSA-h27x-g6w4-24gq
88 next GHSA-h64f-5h5j-jqjh
89 next GHSA-jcc7-9wpm-mj36
90 next GHSA-m34x-wgrh-g897
91 next GHSA-mg66-mrh9-m8jx
92 next GHSA-mq59-m269-xvcx
93 next GHSA-mwv6-3258-q52c
94 next GHSA-q4gf-8mx6-v5v3
95 next GHSA-qpjv-v59x-3qc4
96 next GHSA-qw96-mm2g-c8m7
97 next GHSA-r2fc-ccr8-96c4
98 next GHSA-vfv6-92ff-j949
99 next GHSA-vxf5-wxwp-m7g9
100 next GHSA-w37m-7fhw-fmv9
101 next GHSA-wfc6-r584-vfw7
102 next GHSA-wff4-fpwg-qqv3
103 next GHSA-wr66-vrwm-5g5x
104 next GHSA-x56p-c8cg-q435
105 next GHSA-xv57-4mr9-wg8v
106 react GHSA-g53w-52xc-2j85
107 react GHSA-hg79-j56m-fxgv
108 react-dom GHSA-mvjj-gqq2-p4hw
109 redis GHSA-35q2-47q7-3pc3
110 ws GHSA-2mhh-w6q8-5hxw
111 ws GHSA-3h5v-q93c-6h6q
112 ws GHSA-58qx-3vcg-4xpx
113 ws GHSA-5v72-xg48-5rpm
114 ws GHSA-6663-c963-2gqg
115 ws GHSA-6fc8-4gx4-v693
116 zod GHSA-m95q-7qp3-xv42

View file

@ -0,0 +1 @@
{"queries": [{"package": {"name": "@clickhouse/client", "ecosystem": "npm"}}, {"package": {"name": "@electron-forge/cli", "ecosystem": "npm"}}, {"package": {"name": "@electron-forge/core", "ecosystem": "npm"}}, {"package": {"name": "@electron-forge/maker-zip", "ecosystem": "npm"}}, {"package": {"name": "@msgpack/msgpack", "ecosystem": "npm"}}, {"package": {"name": "@pierre/diffs", "ecosystem": "npm"}}, {"package": {"name": "@tanstack/react-virtual", "ecosystem": "npm"}}, {"package": {"name": "@types/node", "ecosystem": "npm"}}, {"package": {"name": "electron", "ecosystem": "npm"}}, {"package": {"name": "lightweight-charts", "ecosystem": "npm"}}, {"package": {"name": "nats", "ecosystem": "npm"}}, {"package": {"name": "next", "ecosystem": "npm"}}, {"package": {"name": "react", "ecosystem": "npm"}}, {"package": {"name": "react-dom", "ecosystem": "npm"}}, {"package": {"name": "redis", "ecosystem": "npm"}}, {"package": {"name": "typescript", "ecosystem": "npm"}}, {"package": {"name": "ws", "ecosystem": "npm"}}, {"package": {"name": "zod", "ecosystem": "npm"}}]}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
# Stage 02 Patch History & Bypass Review
Scan window: `git log -n "${PIOLIUM_COMMIT_SCAN_LIMIT:-500}" --since="${PIOLIUM_COMMIT_SCAN_SINCE:-60 days ago}" --all` (evaluated with defaults: 500 commits, since 60 days ago). Keyword sweep focused on CVE/security/auth/token/allowlist/deploy/ssh/harden-related commits.
## Relevant historical fixes reviewed
| Commit | Area | Patch summary | Bypass attempts today | Conclusion |
|---|---|---|---|---|
| `8464287` / stash index `bff5334` | Dependency CVEs | Added root `overrides` for `postcss`, `tar`, `tmp`; upgraded `ws` in ingest services from `^8.18.3` to `^8.21.0`. | Checked current root and Docker workspace package manifests: overrides are present in both. Searched all package manifests for direct vulnerable `ws` pins: only ingest services use `^8.21.0`. No sibling service currently pins `ws`, `tar`, `tmp`, or `postcss` directly outside the override coverage. | **Sound** for manifest coverage. Residual risk is lockfile/install-policy dependent; no patch bypass found in source manifests. |
| `5ddfbfa` | Deploy allowlist | Removed broad `deployment/npm/` from `ALLOWED_REMOTE_UNTRACKED`, leaving only the exact signal-cli tarball. | Reviewed current `remoteGitPrecheck()`: it extracts the full untracked path and uses a shell `case` against a generated pattern containing only `deployment/docker/signal-cli-0.14.3-Linux-native.tar.gz`. Because the allowed pattern has no wildcard, paths such as `deployment/docker/signal-cli-0.14.3-Linux-native.tar.gz/evil`, `deployment/npm/x`, or other untracked deployment payloads do not match. Tracked modifications still fail closed. | **Sound**. No alternate deploy precheck path found in current `scripts/deploy.ts`. |
| `2865d56` | Deploy precheck pattern handling | Converted multiple allowed untracked paths into one case alternative pattern instead of emitting malformed case arms. | Current implementation first strips `?? ` into `path` and nests a second `case`, avoiding the earlier malformed pattern/line parsing issue. With a single exact allowlisted file, pattern differential bypass is not apparent. | **Sound**. |
| `39bac1e` plus later deploy hardening | VPS deployment safety | Introduced `scripts/deploy.ts` with local/remote cleanliness checks and non-interactive SSH. Later commits added remote resolution, local-server execution, runtime scopes, and tighter checks. | Checked for command injection through branch/remote names: branch and remote used in remote shell scripts are passed through `shellEscape()`. Checked untrusted config branches: `DEPLOY_NATIVE_SYSTEMCTL_PREFIX` is interpolated into shell scripts unescaped, but this is a local deploy-operator environment override; an attacker who controls it already controls the deployment process. Current-branch deploy requires clean local status and pushes the selected remote before remote switch/pull. | **Sound under intended trust model** (deploy operator controls environment). No remote attacker bypass identified. |
| `e70835e` | Native deploy SSH assumptions | Added `$HOME/.bun/bin` to PATH for native remote precheck/rollout/verification and ensured verification `cd`s into repo. | Not a security fix; reviewed for relocated command execution. It only adds a fixed PATH prefix and does not incorporate attacker-controlled input besides the deploy operator's environment. | **Not security-relevant / no bypass**. |
| `07a9b91` then `7d25608` | Alpaca auth handling | Initially removed deprecated key-pair auth in favor of single bearer token; later restored/normalized current Alpaca key-id + secret handling, including news worker wiring. | Current code centralizes auth in `packages/config/src/alpaca.ts`. Searched for old direct header construction and env names: ingest services call the shared resolver; docs still note legacy bearer fallback. The fallback is intentional compatibility, not an auth bypass, because it is only used when no explicit key-id/secret pair is configured. | **Relocated but currently centralized/sound**. Historical “fix” was corrected by later compatibility patch; no duplicate stale adapter path found. |
## Additional notes
- Several deploy/network commits (`21ec3eb`, `9901b13`/`1c0e2e5`, `cf7ddf3`, `d7e984c`, etc.) are operational hardening/removal of obsolete wrappers. Current repo has a single top-level `deploy` entrypoint invoking `scripts/deploy.ts`; no deprecated `deployment/npm` rollout path remains as an executable bypass surface.
- The `.env.example` and docs still list legacy Alpaca variables, but runtime behavior requires either a complete key-id/secret pair or the explicitly supported legacy bearer token. Missing partial credentials fail closed via `hasAlpacaCredentials()` callers.
## Overall conclusion
No currently exploitable patch bypass was identified in the reviewed security-relevant history. The highest-value checks were the deploy untracked-file allowlist and dependency-CVE manifest coverage; both are presently covered. Recommended follow-up: run dependency audit against the concrete `bun.lock`/container build outputs to confirm the manifest overrides are materialized in deployed artifacts.

View file

@ -0,0 +1,40 @@
# Public Routes Authorization Matrix
Scope: Stage 05 public-route authorization/access-control review. Sources: `piolium/attack-surface/knowledge-base-report.md`, `piolium/attack-surface/architecture-entrypoints.md`, `services/api/src/index.ts`, and Next admin proxy route handlers.
**Roles modeled**: anonymous internet client, authenticated app user (no app auth found), synthetic admin token holder, internal/reverse-proxy peer.
**Hidden control channels**
- API bind/proxy exposure: `API_HOST` defaults to `127.0.0.1`, but any reverse-proxy route or `API_HOST=0.0.0.0` exposes all public API/WS routes without handler-level re-check.
- Synthetic admin API accepts `Authorization: Bearer` and fallback `x-synthetic-admin-token` (`services/api/src/index.ts:320-327`); API admin routes are otherwise guarded by `authenticateSyntheticAdminRequest` (`services/api/src/index.ts:1326-1351`).
- Next admin proxy target and availability are env controlled: `NEXT_PUBLIC_SYNTHETIC_ADMIN`, `NEXT_PUBLIC_API_URL`, and server-side `SYNTHETIC_ADMIN_TOKEN` (`apps/web/app/api/admin/synthetic/shared.ts:10-22`).
- Next admin proxy unconditionally injects the bearer token on behalf of the requester (`apps/web/app/api/admin/synthetic/shared.ts:44-55`), so browser caller identity is not re-checked.
- WebSocket upgrade routes check only method/path before `serverRef.upgrade` (`services/api/src/index.ts:1846-1939`); no Origin/auth/rate guard observed.
| # | Public route / operation | Handler | Expected checks | Actual checks by role | Middleware / proxy-derived identity | Hidden controls | Anomaly / draft |
|---:|---|---|---|---|---|---|---|
| 1 | `GET /health` | `services/api/src/index.ts:1360` | Public health | anon: allowed; auth/admin/internal: allowed | none | bind/proxy only | none |
| 2 | API `GET /admin/synthetic/status` | `services/api/src/index.ts:1364` | Synthetic admin only | anon/auth: 401; token-holder: allowed; internal: allowed only with token | `Authorization` or `x-synthetic-admin-token` | `SYNTHETIC_CONTROL_ENABLED`, backend mode | none |
| 3 | API `GET /admin/synthetic/control` | `services/api/src/index.ts:1372` | Synthetic admin only | anon/auth: 401; token-holder: allowed | same as above | same as above | none |
| 4 | API `PUT /admin/synthetic/control` | `services/api/src/index.ts:1380` | Synthetic admin only | anon/auth: 401; token-holder: can mutate control state | same as above | same as above | none at API layer |
| 5 | Next `GET /api/admin/synthetic/status` | `apps/web/app/api/admin/synthetic/status/route.ts:5` | Admin/browser session or equivalent server-side auth before proxying | anon/auth: allowed when feature/env configured; backend receives server bearer token; synthetic admin role effectively conferred | server route injects `Authorization: Bearer ${SYNTHETIC_ADMIN_TOKEN}` | `NEXT_PUBLIC_SYNTHETIC_ADMIN=1`, `NEXT_PUBLIC_API_URL` | **p5-001** |
| 6 | Next `GET /api/admin/synthetic/control` | `apps/web/app/api/admin/synthetic/control/route.ts:5` | Admin/browser session | anon/auth: allowed when feature/env configured; reads admin control | server token injection | same | **p5-001** |
| 7 | Next `PUT /api/admin/synthetic/control` | `apps/web/app/api/admin/synthetic/control/route.ts:11` | Admin/browser session + CSRF/origin intent | anon/auth: allowed when feature/env configured; body forwarded with server token | server token injection | same | **p5-001** |
| 8 | Recent REST reads: `GET /prints/options`, `/nbbo/options`, `/prints/equities`, `/quotes/equities`, `/joins/equities`, `/dark/inferred`, `/flow/packets`, `/flow/smart-money`, `/flow/classifier-hits`, `/flow/alerts`, `/news` | `services/api/src/index.ts:1407-1533` | Public per current architecture, or proxy/firewall if proprietary data | anon/auth/admin/internal: allowed; zod/limit parsing only | none | `API_HOST`/reverse proxy | review target: proprietary data scraping if exposed |
| 9 | Filtered/range REST reads: `GET /prints/equities/range`, `/candles/equities` | `services/api/src/index.ts:1438,1460` | Public per current architecture, bounded query params | anon/auth/admin/internal: allowed; parameter validation/limit only | optional Redis cache selected by request `cache` | bind/proxy, cache flag | none filed |
| 10 | Alert context helper route(s) | `services/api/src/index.ts:1539`, `:1670` | Public/read-only, bounded trace id | anon/auth/admin/internal: allowed; trace id parse/length check on regex path | none | bind/proxy | none filed |
| 11 | History REST reads: `/history/options`, `/history/nbbo`, `/history/equities`, `/history/equity-quotes`, `/history/equity-joins`, `/history/flow`, `/history/smart-money`, `/history/classifier-hits`, `/history/alerts`, `/history/inferred-dark`, `/history/news` | `services/api/src/index.ts:1558-1656` | Public per current architecture, bounded cursors/limits | anon/auth/admin/internal: allowed; cursor/limit validation only | none | bind/proxy | review target: bulk history extraction if not intended public |
| 12 | Object lookup reads: `GET /flow/packets/:id`, `/option-prints/by-trace`, `/equity-joins/by-id` | `services/api/src/index.ts:1664,1681,1714` | Public/read-only if market data IDs are non-sensitive | anon/auth/admin/internal: allowed; no actor ownership model present | none | bind/proxy | none filed; no user/tenant objects identified |
| 13 | Support lookup: `POST /lookup/options-support` | `services/api/src/index.ts:1687` | Public/read-only aggregation with body validation | anon/auth/admin/internal: allowed; zod body schema; no auth | none | bind/proxy | none filed |
| 14 | Replay reads: `/replay/options`, `/replay/nbbo`, `/replay/equities`, `/replay/equity-quotes`, `/replay/equity-candles`, `/replay/equity-joins`, `/replay/inferred-dark`, `/replay/flow`, `/replay/smart-money`, `/replay/classifier-hits`, `/replay/alerts` | `services/api/src/index.ts:1720-1838` | Public per current architecture, bounded cursors/limits | anon/auth/admin/internal: allowed; zod parsing/limits only | none | bind/proxy | review target: bulk replay extraction if proprietary |
| 15 | Legacy WebSockets: `/ws/options`, `/ws/options-nbbo`, `/ws/equities`, `/ws/equity-candles`, `/ws/equity-quotes`, `/ws/equity-joins`, `/ws/inferred-dark`, `/ws/flow`, `/ws/classifier-hits`, `/ws/smart-money`, `/ws/alerts` | `services/api/src/index.ts:1846-1926`, `:1958-1978` | Public live market streams or edge auth/rate/origin guard if proprietary | anon/auth/admin/internal: upgrade allowed by path; no Origin/auth check | none | bind/proxy, WebSocket origin not checked | review target: unauth streaming/resource exposure |
| 16 | Live WebSocket subscription API: `GET /ws/live` + subscribe/unsubscribe/ping messages | `services/api/src/index.ts:1934`, `:1982-2008` | Public live API with schema limits; auth/rate/origin if proprietary | anon/auth/admin/internal: upgrade allowed; messages schema-validated but no auth | subscription data from client message | bind/proxy, WebSocket origin not checked | review target: unauth streaming/resource exposure |
| 17 | Next public pages `/`, `/tape`, `/signals`, `/charts`, `/news`, `/options`, `/replay`, `/frontend-cooker` | `apps/web/app/**` | Public UI | anon/auth/admin/internal: allowed by file routing | browser calls API configured by env | `NEXT_PUBLIC_API_URL` exposed to client | none filed |
## Anomalies promoted to drafts
- `piolium/findings-draft/p5-001-public-next-admin-proxy-confers-synthetic-admin.md` — public Next.js synthetic admin proxy routes inject the server admin token without authenticating the browser caller.
## Notes
No user/account/tenant ownership model was found in the enumerated market-data API, so public data endpoints were not filed as missing-guard findings solely because they lack auth. They remain deployment-policy review targets because the KB notes proprietary research value and exposure depends on reverse proxy/bind settings.

View file

@ -0,0 +1,31 @@
# Stage 04 Source-to-Sink Flows (All Severities)
Tooling note: `codeql` and `semgrep` were not present on PATH. Per instruction, Stage 04 fell back to grep/read plus Phase 3 candidate prioritization. Custom placeholder CodeQL queries and Semgrep rules are stored under `piolium/codeql-queries/` and `piolium/semgrep-rules/`.
## High-priority flows
| ID | Source | Path | Sink | Security relevance | Draft |
|---|---|---|---|---|---|
| F-001 | Alpaca/provider news `item.content` (`services/ingest-news/src/index.ts:78`) | `content_html` -> NATS/ClickHouse -> `sanitizeNewsHtml` regex (`apps/web/app/terminal.tsx:1272`) | `dangerouslySetInnerHTML` (`apps/web/app/terminal.tsx:5009`) | Stored XSS via provider-controlled HTML | `p4-001` |
| F-002 | Remote WebSocket upgrade and messages (`services/api/src/index.ts:1844`, `1959`) | unauthenticated `serverRef.upgrade` -> socket set/subscription -> `liveState.getSnapshot` | `socket.send` fanout/snapshot (`services/api/src/index.ts:1982`) | Unauthenticated data streaming/resource abuse | `p4-002` |
| F-003 | Remote HTTP query/path params (`services/api/src/index.ts:1357`) | manual routes parse params -> storage fetchers | ClickHouse `client.query` in `packages/storage/src/clickhouse.ts` | Public data exfil if API exposed | `p4-003` |
| F-004 | Next admin proxy route body/path + env base (`apps/web/app/api/admin/synthetic/*.ts`) | fixed route paths -> `new URL(path, NEXT_PUBLIC_API_URL)` -> bearer header from `SYNTHETIC_ADMIN_TOKEN` | `fetch(url.toString())` (`shared.ts:51`) | Environment-controlled SSRF/control channel; path fixed, so downgraded | none |
| F-005 | HTTP admin control body + auth header (`services/api/src/index.ts:1339`, `1386`) | bearer token compare -> `SyntheticControlStateSchema.parse` | `writeSyntheticControlState` (`services/api/src/index.ts:1387`) | Hidden control channel; gated by token/feature flag | none |
| F-006 | WebSocket live message bytes (`services/api/src/index.ts:1959`) | `TextDecoder` -> `JSON.parse` -> Zod schemas | subscription maps/live snapshots | DoS potential; needs message-size/connection quotas | covered by `p4-002` |
| F-007 | Env/config Python binary and adapter settings | `buildArgs(trimmed)` / `args` arrays | `Bun.spawn` (`databento.ts:305`, `ibkr.ts:92`) | Local/env-controlled subprocess path; no shell, downgraded to env/admin-only | none |
| F-008 | User query arrays (`trace_id`, `id`, filters) | `url.searchParams.getAll` -> query-builder helpers (`quoteString`, `buildStringList`, `clamp*`) | ClickHouse template queries | SQLi mostly mitigated by escaping/clamps; query DoS still worth limits | none |
## Hidden-control-channel review
- `authorization` / `x-synthetic-admin-token` in `services/api/src/index.ts:327-333`: affects admin control authorization; correctly checked for `/admin/synthetic/*`, absent from data routes.
- `NEXT_PUBLIC_SYNTHETIC_ADMIN`, `NEXT_PUBLIC_API_URL`, `SYNTHETIC_ADMIN_TOKEN` in `apps/web/app/api/admin/synthetic/shared.ts`: controls whether the admin proxy exists and where it sends privileged bearer requests.
- `window.location.host` in `apps/web/app/terminal.tsx:1024/1045`: client-side API/WS endpoint selection follows current origin; relevant to reverse-proxy host trust but not a server-side SSRF.
- Response `content-type` checks in `terminal.tsx` and scripts: robustness checks, not auth/routing controls.
## Dropped/low candidates
- Test secrets in `*.test.ts`: source-controlled test literals only.
- `exec` matches in ClickHouse client: SQL execution/query API, not OS command execution.
- Static `redirect("/")`/`redirect("/options")`: no user-controlled URL.
- `Array.join` path-traversal matches: mostly string formatting/query construction false positives.
- Dev/deploy `Bun.spawn`/`spawnSync` in scripts: local tooling/admin context unless used by untrusted CI input.

View file

@ -0,0 +1,21 @@
# Stage 07 — Specification, Framework Contract & Parser Gaps
## Scope
Phase 3 identified no formal application RFC/spec commitments, so this stage focused on de facto framework/runtime contracts: Bun HTTP/WebSocket routing, Next.js route-handler proxying, Docker/proxy deployment assumptions, and internal infrastructure trust channels.
## High-signal gaps retained
1. **Unauthenticated infrastructure services exposed by root Compose**`docker-compose.yml` publishes ClickHouse, Redis, and NATS directly on host ports with no credentials/TLS/ACL configuration. This violates the deployment contract implied by the production compose file, where these services are internal-only. Draft: `piolium/findings-draft/p7-001-root-compose-exposes-unauth-infra.md`.
## Reviewed but not retained as new P7 findings
- **WebSocket Origin/auth contract**: Bun upgrades `/ws/*` by path only and does not inspect `Origin` or auth. This is already covered by existing draft `p4-002-unauthenticated-websocket-market-data-streams.md`; no duplicate P7 draft was created.
- **Public unauthenticated REST market-data APIs**: already covered by `p4-003-public-api-exposes-queryable-market-history.md`.
- **Provider HTML rendering/sanitization**: already covered by `p4-001-stored-xss-news-html-regex-sanitizer.md`.
- **Next.js synthetic admin proxy target (`NEXT_PUBLIC_API_URL`)**: server-side admin proxy derives its target from a public/build-time env var. This is a hardening concern and config footgun, but I did not retain it as Medium+ without an external attacker path to set deployment env or read the server-only `SYNTHETIC_ADMIN_TOKEN`.
- **Encoded path parsing for `/flow/alerts/:trace/context` and `/flow/packets/:id`**: manual regex checks occur on `URL.pathname` before `decodeURIComponent`, allowing `%2F` inside decoded IDs. Current impact appears limited to identifier lookup, not authorization/routing bypass, so it was not retained.
## Framework-contract conclusion
The most concrete new Stage 07 gap is a deployment-mode differential: production compose relies on internal-only Docker networking for ClickHouse/Redis/NATS, while the root compose publishes those same unauthenticated services on all interfaces by default. If the root compose is used on a workstation/VPS with reachable host ports, a network attacker can publish forged NATS events, read/write Redis state, or query/alter ClickHouse data outside any API-layer checks.

View file

@ -0,0 +1,36 @@
# State Machine & Concurrency Summary
Stage 06 reviewed the Phase 3 KB, CodeQL structural artifacts, ClickHouse DDL/model files, NATS/JetStream consumers, Redis/cache usage, and admin state paths.
## State-holding entities catalogued
1. `synthetic_control.global` (NATS KV) — `SyntheticControlState` fields: `preset_id`, `coverage_assist`, `coverage_window_minutes`, `shared_seed`, `profile_weights`, `updated_at`, `updated_by`.
2. `flow_packets` — append-only derived event state; deterministic `id`/`trace_id`; `MergeTree ORDER BY (source_ts, seq)`.
3. `smart_money_events` — append-only derived event state; `event_id`; `MergeTree ORDER BY (source_ts, seq)`.
4. `classifier_hits` — append-only derived classifier state; `trace_id`; `MergeTree ORDER BY (source_ts, seq)`.
5. `alerts` — append-only alert state; `trace_id`, `severity`; `MergeTree ORDER BY (source_ts, seq)`.
6. `equity_candles` — aggregate/counter-like fields: `volume`, `notional`, `trade_count`; `MergeTree ORDER BY (underlying_id, interval_ms, ts)`.
7. `news` — lifecycle/revision-like fields: `published_ts`, `updated_ts`; uses `ReplacingMergeTree(updated_ts)`.
8. `option_prints`, `option_nbbo`, `equity_prints`, `equity_quotes`, `equity_print_joins`, `inferred_dark` — append-only event stores with timestamps/sequence cursors.
No balance/credit/payment/quota inventory was found. No payments/webhooks were identified.
## Concurrency primitives observed
- Language-level locks/mutexes: none in application services.
- Database transactions / `SELECT FOR UPDATE` / advisory locks: none found.
- Distributed locks / Redis `SETNX` / Redlock: none found.
- JetStream manual acknowledgement is used (`buildDurableConsumer` sets `manualAck()` / `ackExplicit()`), making idempotent consumers important.
- NATS KV is used for synthetic control state, but updates use unconditional `kv.put` rather than a revision/CAS update.
## Idempotency infrastructure
- Present only as in-memory/UI dedupe and short-lived compute dedupe maps (`recentStructureEmits`, client-side/live dedupe). This does not survive restarts or JetStream redelivery.
- No persisted `idempotency_key`, `processed_events`, request log, replay store, Redis idempotency key, or durable event-processing ledger was found.
## Drafts filed
- `p6-001-jetstream-redelivery-duplicates-derived-events.md` — idempotency gap on JetStream redelivery and append-only ClickHouse derived tables (HIGH).
- `p6-002-synthetic-control-lost-update.md` — stale-read/lost-update in full-object synthetic control writes without revision checks (MEDIUM).
Split by class: idempotency: 1; stale-read: 1.

View file

@ -0,0 +1,17 @@
# Phase 12 Variant Summary
Variant analysis reviewed surviving findings in `piolium/findings-draft/` and searched code/attack-surface artifacts for sibling sources, sinks, and flow shapes. `piolium/attack-pattern-registry.json` was not present, so no registry update could be made.
## Confirmed variants
1. `piolium/findings-draft/p12-001-unauthenticated-nats-market-event-injection.md` — expands the confirmed unauthenticated `flow.news` producer-impersonation flaw to the other trusted market/derived NATS subjects consumed by API, compute, and candles.
2. `piolium/findings-draft/p12-002-candles-jetstream-redelivery-duplicates-derived-candles.md` — same JetStream side-effects-before-ack idempotency gap as compute, present in the candles worker.
## Searches performed
- HTML injection/XSS: only `apps/web/app/terminal.tsx` uses `dangerouslySetInnerHTML` and the regex sanitizer pattern.
- Admin proxy: only `apps/web/app/api/admin/synthetic/*` injects a server bearer token into public Next route proxying.
- WebSocket auth/origin: unauthenticated upgrade pattern is centralized in `services/api/src/index.ts`; no additional WS servers found.
- NATS producer trust: API consumer binding matrix and worker subscriptions show additional subjects accepting schema-only messages from the unauthenticated broker.
- JetStream redelivery/idempotency: candles worker matches the compute side-effect-before-ack shape.
- Infrastructure exposure: root compose exposure finding remains centralized to root `docker-compose.yml`; production compose does not publish infra ports directly in the same way.

128
piolium/audit-state.json Normal file
View file

@ -0,0 +1,128 @@
{
"audits": [
{
"audit_id": "2026-05-27T05:18:10.317Z",
"mode": "deep",
"started_at": "2026-05-27T05:18:10.317Z",
"completed_at": "2026-05-27T05:38:26.877Z",
"status": "complete",
"phases": {
"P1": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:18:10.342Z",
"completed_at": "2026-05-27T05:20:06.688Z"
},
"P2": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:20:06.689Z",
"completed_at": "2026-05-27T05:21:18.561Z"
},
"P3": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:21:18.562Z",
"completed_at": "2026-05-27T05:24:17.798Z"
},
"P4": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:24:17.800Z",
"completed_at": "2026-05-27T05:27:39.637Z"
},
"P5": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:27:39.640Z",
"completed_at": "2026-05-27T05:29:12.056Z"
},
"P6": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:27:39.991Z",
"completed_at": "2026-05-27T05:29:28.102Z"
},
"P7": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:27:40.151Z",
"completed_at": "2026-05-27T05:28:55.011Z"
},
"P8": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:29:28.109Z",
"completed_at": "2026-05-27T05:30:58.598Z"
},
"P9": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:30:58.599Z",
"completed_at": "2026-05-27T05:32:50.466Z"
},
"P10": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:32:50.468Z",
"completed_at": "2026-05-27T05:34:14.783Z"
},
"P11": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:34:14.789Z",
"completed_at": "2026-05-27T05:35:44.121Z"
},
"P12": {
"status": "complete",
"attempt": 1,
"max_attempts": 6,
"started_at": "2026-05-27T05:35:44.122Z",
"completed_at": "2026-05-27T05:36:59.883Z"
},
"P13": {
"status": "skipped",
"started_at": "2026-05-27T05:36:59.891Z",
"completed_at": "2026-05-27T05:36:59.892Z"
},
"P14": {
"status": "skipped",
"started_at": "2026-05-27T05:36:59.892Z",
"completed_at": "2026-05-27T05:36:59.894Z"
},
"P15": {
"status": "complete",
"attempt": 2,
"max_attempts": 6,
"started_at": "2026-05-27T05:36:59.896Z",
"completed_at": "2026-05-27T05:38:26.848Z"
},
"P16": {
"status": "complete",
"started_at": "2026-05-27T05:38:26.850Z",
"completed_at": "2026-05-27T05:38:26.851Z"
},
"P17": {
"status": "complete",
"started_at": "2026-05-27T05:38:26.852Z",
"completed_at": "2026-05-27T05:38:26.876Z"
}
},
"agent_sdk": "pi",
"commit": "ffbdbc337638004be49775c85a2f0b10b7e55563",
"branch": "security-audit",
"history_available": true
}
]
}

View file

@ -0,0 +1,47 @@
# Security Audit Report: Islandflow
## Executive Summary
Stage 15 final report assembly completed for the Islandflow `/piolium-deep` audit workspace. The repository presents a multi-service market-data platform with public web/API/WebSocket entrypoints, NATS/JetStream eventing, ClickHouse/Redis persistence, ingest workers, synthetic-admin controls, and an Electron shell. No promoted final finding directories were present under `piolium/findings/` during this assembly, so this report consolidates the available attack-surface and methodology artifacts rather than listing confirmed packaged findings.
## Findings by Severity
- Critical: 0
- High: 0
- Medium: 0
No promoted confirmed finding directories were present under `piolium/findings/` at assembly time. Earlier-stage candidate and chamber outputs remain available under `piolium/findings-draft/`, `piolium/chamber-workspace/`, and `piolium/adversarial-reviews/`, but no standalone `report.md` finding packages were available to link as final confirmed findings.
## Attack Surface Summary
The audit identified the primary exposed and security-relevant surfaces as: unauthenticated market-data REST and WebSocket routes in `services/api`, Next.js synthetic-admin proxy routes, external feed ingestion paths, NATS/JetStream subjects and KV state, ClickHouse query/insert sinks, Redis live/candle caches, Electron navigation/open-external boundaries, and Docker/edge deployment bindings.
Key supporting artifacts:
- [Knowledge Base / Threat Model](piolium/attack-surface/knowledge-base-report.md)
- [Architecture Entrypoints](piolium/attack-surface/architecture-entrypoints.md)
- [Manual Attack Surface Inventory](piolium/attack-surface/manual-attack-surface-inventory.md)
- [Public Routes Authorization Matrix](piolium/attack-surface/public-routes-authz-matrix.md)
- [Source/Sink Flow Review](piolium/attack-surface/source-sink-flows-all-severities.md)
- [Cross-Service Edges](piolium/attack-surface/cross-service-edges.md)
- [Candidate Scan Summary](piolium/attack-surface/candidates-summary.md)
- [Advisory Summary](piolium/attack-surface/advisory-summary.md)
- [Patch Bypass Summary](piolium/attack-surface/patch-bypass-summary.md)
- [Spec Gap Summary](piolium/attack-surface/spec-gap-summary.md)
- [State/Concurrency Summary](piolium/attack-surface/state-concurrency-summary.md)
- [Variant Summary](piolium/attack-surface/variant-summary.md)
## Coverage Gaps
- `piolium/findings/` was not present or contained no promoted finding packages at final assembly time; therefore no final per-finding reports or PoC links could be included.
- Candidate drafts and review evidence exist outside the promoted findings directory and should be reviewed before treating this as a no-findings audit result.
- Final report completeness depends on prior-stage promotion from drafts to `piolium/findings/<ID>-<slug>/report.md`; that promotion was not observable in this workspace.
## Methodology Notes
The audit followed the deep piolium workflow: advisory and architecture reconnaissance, attack-surface inventory, candidate scanning, custom SAST/source-sink review, structured review chambers, adversarial verification for higher-risk candidates, and final assembly. Chamber evidence is available at [`piolium/chamber-workspace/index.md`](piolium/chamber-workspace/index.md), with cluster debates covering news XSS, data exposure, synthetic admin proxying, concurrency, and infrastructure/bus risks. Static and structural analysis artifacts are available under `piolium/codeql-artifacts/`, `piolium/semgrep-rules/`, and `piolium/attack-surface/`.
## Assembly Checks
- Finding report size check: passed for every directory under `piolium/findings/` that existed; no promoted directories were found.
- Required final report written: `piolium/final-audit-report.md`.