Skip to content

Core services security audit and fix plan

Status: Current | Last reviewed: 2026-09-17

This report covers security vulnerabilities, not just open-source licenses, in the local ai-orchestrator, ai-manager, surface-app and async-agent versions. Use it to sequence remediation and distinguish findings from scan coverage gaps. It records the baseline; the broader fixes below have not been applied locally.

Results

Each cell is Critical / High / Medium. Low findings are excluded. Dependency counts deduplicate advisory IDs within a service. Source counts are Snyk Code finding identities. The same advisory can affect multiple services; do not interpret the sum as distinct vulnerabilities or proven exploits.

Local service Dependency vulnerabilities Source security findings Container OS findings
ai-orchestrator 2 / 25 / 20 0 / 0 / 6 3 / 10 / 4, base stage only
ai-manager 4 / 34 / 48 0 / 25 / 34 0 / 0 / 0
surface-app 6 / 40 / 52 0 / 4 / 9 0 / 0 / 0
async-agent 0 / 0 / 0 0 / 1 / 0 3 / 10 / 4

There are 231 dependency advisory instances, 79 source findings and 34 container advisory instances across these service/scan combinations. The full CSV inventory includes every finding ID, severity, affected version, reported fixed versions, dependency paths or source location, and initial review status. The JSON summary preserves the counts.

The scans also produced 24 license-policy notices, listed separately in the CSV: ai-orchestrator has four High and three Medium; ai-manager and surface-app each have seven Medium; async-agent has three Medium. These are excluded from every security count above.

What was scanned

  • Snyk Open Source: known security advisories in dependency graphs. Node scans include development dependencies; the CSV identifies findings reachable only through development dependencies. For example, surface-app's Critical esbuild, flatted and Vitest findings belong to its development toolchain, while its Next.js and undici findings have runtime dependency paths.
  • Snyk Code: static analysis for SQL injection, XSS, SSRF, code injection, unsafe redirects, prototype pollution, regex denial of service, JWT handling and related risks. Tests and public diagnostic assets are included.
  • Snyk Container: OS packages in freshly built images. The frontend reports enumerate Alpine packages; zero OS findings does not mean their Next.js/application dependencies are clean. Those appear in the dependency scan.

Scans used --severity-threshold=medium. Dependency and container scans used --ignore-policy; source scans used --include-ignores. No suppression or license acceptance was added.

The snapshot starts at local commit 596c0f4803be1b34ea3404c3473d11e9bd9fd08f and includes 90 uncommitted changes in the four services and their shared build inputs. The initial audit commit is 8d6fb448; a manifest hashes 4,494 source/build inputs. Later audit commits change scan setup and inventory only. The original working checkout and running services were not changed by the scans.

Installed public package versions in ai-orchestrator match its frozen uv.lock; three missing lock entries are platform-specific packages. Installed Node package versions match their lockfiles after normalizing ElevenLabs' leading v; optional/platform package entries absent on this host remain in the scan. Async-agent has ranged production requirements, so an additional scan reproduced its exact local installed package versions. Both that scan and the fresh requirements resolution found zero Medium-or-higher dependency security advisories.

Coverage limits

Ai-orchestrator's full image requires proprietary Krisp ZIP archives that are present only locally. Its container scan therefore covers the unchanged runtime-base stage, not the final image, PortAudio runtime additions or Krisp binaries. Its public Python dependency graph and source were scanned; the proprietary runtime still needs a complete image/vendor assessment.

Images were rebuilt from the snapshot Dockerfiles and current registry bases. These are build assessments, not scans of live official Dev/QA containers. Static findings have not all been proven exploitable. In particular, existing URL guards and intentionally public JWT constants produce review candidates.

Reproducible evidence

The private audit branch is audit/core-snyk-local-20260917. It is an assessment snapshot containing local work in progress and must not be merged as a feature PR.

Evidence GitHub Actions run
Container builds and initial source scans 35268963279
Successful source/dependency scans for all four services 35269518225
Exact locally installed async-agent dependencies 35269841811

The first run failed dependency setup for three services; those failures are not counted as clean scans. The successful retry supplied the source/dependency results above. Run 35269208930 was canceled while queued and supplies no evidence. JSON, SARIF, scanner versions, image metadata and input hashes are retained in the private Actions artifacts for 14 days.

Fix plan

The version targets below come from the scan's fixed-version data. They are compatibility candidates, not upgrades already tested against the applications. Use separate PRs for each workstream so an unrelated API migration cannot hold up an available security patch.

1. Patch Critical runtime dependencies

Service Current package Candidate fix Implementation and verification
Both frontends Next.js 16.2.9 16.3.3 or later patched 16.x Update Next.js and matching lint config, regenerate locks, run typecheck/unit tests, build standalone images and test login/embed/session flows
Both frontends undici 7.28.0 7.29.1 or later patched 7.x Update both direct requirements and overrides; verify certificate rejection, outbound HTTP and isomorphic-dompurify paths
ai-manager proxy-addr 2.0.7 through MCP SDK → Express 2.0.8 Refresh the transitive lock entry or use a scoped compatible override; test MCP authentication and proxy-address handling
ai-orchestrator google-adk 1.32.0 1.38.0 within the existing <2 range Raise the direct floor and regenerate uv.lock; test ADK/A2A integration and tool authorization
ai-orchestrator sqlparse 0.5.5 through Google Spanner/ADK 0.6.0 Resolve with the ADK/Spanner dependency family; verify compatibility rather than forcing an incompatible override

These address Next.js traversal/optimization advisories, undici certificate validation, proxy-addr impersonation, ADK authorization and sqlparse code injection. Advisory IDs and all paths are in the CSV.

2. Patch the Debian bases

Apply the shared-base upgrade approach from PR #705 to the local async-agent Dockerfile and ai-orchestrator's runtime base, then rebuild with fresh layers.

Package Reported fixed Debian 13 version
perl-base 5.40.1-6+deb13u1
libsqlite3-0 3.46.1-7+deb13u2
libpcre2-8-0 10.46-1~deb13u2
gzip 1.13-1+deb13u1

These upgrades cover 13 of the 17 Medium-or-higher OS advisories on each scanned Debian image. Four remain without a fixed Debian 13 package in the scan: zlib, attr, and two acl advisories, comprising three High and one Medium. Keep those visible and track upstream releases; do not remove required libraries or mix Debian unstable packages into the runtime to change a count. Obtain the Krisp build inputs through the existing vendor process and scan ai-orchestrator's complete final image before closing its container workstream.

3. Close source trust-boundary risks

Priority Finding group and evidence Proposed change and acceptance check
First surface-app SSRF: proxy.ts constructs the session-check destination from forwarded headers and sends cookies to it Use a fixed trusted internal origin or share the session verifier directly. Test hostile host/protocol headers and redirects; cookies must never be sent to an arbitrary destination
First ai-orchestrator's four Code Injection traces reach python_script_executor.py, which compiles and executes stored Python in the service process Route these legacy tools through code-executor with the existing sandbox limits and explicit integration grants. Preserve tool outputs and prove user code cannot access the orchestrator process's environment or files
Next surface-app's three JWT-decode findings, especially the reentry decision in session exchange Verify existing cookie JWT signatures/issuer/audience/expiry before using them to authorize reentry. Test forged cookies and replayed bootstrap tokens; keep display-only decoding separate
Next DOM XSS, unsafe redirects and postMessage findings across both frontends, including the embed SDK Validate URL scheme and destination, constrain return paths, enforce exact message origins/source windows and review public diagnostic HTML. Test javascript/data URLs, external redirect targets and unrelated message senders
Next ai-manager prototype pollution and regex/SQL traces in tool editing and authoring helpers Trace each reported sink, reject prototype keys in object-path writes, retain parameterized SQL and bound regex work. Add regression tests for the actual sink rather than only its caller
Review Cloud/MCP SSRF findings in ai-manager and ai-orchestrator Existing region validators, safeFetch and initial URL guards must be included in the assessment. Test redirect hops, DNS rebinding and credential forwarding before deciding whether each finding needs code or a scanner review

The scanner rates the stored-Python execution traces Medium. Their location inside a shared runtime is why this plan places the sandbox boundary ahead of many dependency Mediums; the plan does not claim a demonstrated production exploit.

4. Refresh remaining High/Medium dependencies

Workstream Main target families Constraints to preserve
ai-orchestrator aiohttp ≥3.14.3, cryptography ≥50.0.0, Pillow ≥12.3.0, pyasn1 ≥0.6.4, MCP ≥1.28.1, json-repair ≥0.60.1, httplib2 ≥0.32.0; Authlib, cert/HTTP helpers and parsing utilities Update the existing security floors and uv.lock together. Check the MCP API generation before allowing a major upgrade. Remove the exact python-dotenv 1.1.1 pin in favor of a patched compatible release
Both frontends DOMPurify ≥3.4.13, Mermaid ≥11.16.1, PostCSS ≥8.5.23, sharp ≥0.35.4, js-yaml ≥4.3.2, next-intl ≥4.9.2; nanoid, AJV and matching fast-uri versions Cover nested copies and existing overrides. Test Markdown/SVG sanitization, image processing and schema validation
ai-manager Hono ≥4.13.5, @hono/node-server ≥1.19.17, proxy-addr, qs, body-parser, browserslist and ts-deepmerge Replace stale override floors, including the exact brace-expansion 2.1.2 override. Treat ts-deepmerge's major update as an API change
surface-app tooling Vite/Vitest/esbuild, flatted, Rollup, tar, picomatch and the older AI SDK/provider-utils tree Upgrade compatible parent packages together. The critical esbuild/flatted/Vitest findings are development-only paths; also cover the High @vitest/mocker advisory rather than stopping at the first patched Vitest version

Surface-app's AI SDK 5/provider-utils 3 tree needs a compatible family upgrade: one provider-utils advisory only lists patched 4.x/5.x versions. Do not force a different provider-utils major under callers that expect 3.x. The CSV carries the remaining advisory-specific minima, including packages absent from this table. NLTK has a Medium advisory with no fixed version in the scan; assess its reachable use and track upstream separately.

For each dependency PR, run the affected service's lint/typecheck and tests, rebuild its production image, and rerun all applicable Snyk scans at Medium. Preserve the project-specific lockfile/install strategy. New overrides need a reason and a removal condition; avoid one blanket upgrade across four runtimes.

5. Review false positives and license notices separately

Several “hardcoded secret” findings point to public JWT issuer/audience names or redaction masks, not credentials: the constants in ai-manager/embed-jwt.ts, surface-app/session-cookie.ts and the tenant settings SECRET_MASK exports are examples. Do not rotate public identifiers or weaken masking to silence these. Review test fixtures and every remaining reported location individually.

Async-agent's SQL Injection finding 4ccb1c24-3c6b-4de7-9d71-ca9c04ffa00d follows authentication and database results into remote tool dispatch. Reviewed queries bind $1/$2; the sandbox payload is JSON. The PR rerun reports the same finding at resolve_and_execute_mcp_tool, whose lookup also uses bound UUID parameters. It remains open pending Security/Snyk false-positive review. Local .snyk issue ignores do not resolve Snyk Code findings.

Handle the 24 license-policy notices as a separate approval/replacement task, including ai-orchestrator's GPL/LGPL and unknown-license reports. They do not substitute for or reduce the security remediation work.

PR #705 outcome

PR #705 now includes commits 6b208feb and beb9d3c4. The patch upgrades inherited Debian packages, names the sandbox HTTP transport explicitly, validates tenant UUIDs at authentication and adds security regression coverage.

Validation: 177 async-agent tests passed, targeted Python lint passed, and the production image built and imported successfully as UID 10001. The verified Snyk rerun reports zero Critical and three High container findings, down from three Critical and ten High. Its dependency security scan is clean. The three container findings have no fixed Debian 13 package; the one High SQL source finding remains for review. No alert has been suppressed. This PR patch is separate from the unchanged local baseline above.

See also