File Browser proxy-auth, SiYuan local-app, Authorizer OAuth, and Pimcore CMS boundary checks¶
Source: hourly offensive-security scan, 2026-07-10 late GitHub advisory wave with 19:32 and 20:37 UTC follow-ups. Primary entries: GHSA-xqp3-jq6g-x3qm / CVE-2026-54089, GHSA-m93h-4hw7-5qcm / CVE-2026-54088, GHSA-hvr9-72v2-fff3 / CVE-2026-54069, GHSA-gcm7-57gf-953c / CVE-2026-54068, GHSA-p4m3-mgmm-c664 / CVE-2026-54066, GHSA-w7cg-whh7-xp28 / CVE-2026-54070, GHSA-mvjr-vv3c-w4qv / CVE-2026-54067, GHSA-5xfx-xj4h-5p7r / CVE-2026-54158, GHSA-56mp-4f3v-fgj2 / CVE-2026-50551, GHSA-h29v-hj44-q8cv / CVE-2026-54072, and the Pimcore updates GHSA-wc7j-g8wx-m2qx, GHSA-r2f4-ff2p-xc64, GHSA-jwcc-gv4m-93x6, GHSA-36fc-7wjg-mfvj, GHSA-332x-r494-54fq, GHSA-h4ph-crvj-9h92, and GHSA-3234-gxc3-pq6f.
This batch is durable because each item maps to a repeatable operator boundary: a reverse-proxy identity header reaching an app that is also directly exposed, desktop/browser origins crossing into loopback note-app administrator APIs, unauthenticated template helpers crossing into local SQLite reads, publish-mode path normalization missing a second decode, marketplace or synced content crossing into trusted desktop rendering, OAuth implicit-flow redirect URIs missing client allowlist checks, and CMS backend feature permissions drifting away from object-level permissions, SQL construction, or deserialization sinks.
Authorized validation only
Keep proofs to disposable File Browser, SiYuan, Authorizer, and Pimcore labs. Use fake proxy usernames, synthetic note blocks, marker-only workspace files, harmless DOM markers, owned redirectors, disposable OAuth clients/users, seeded CMS assets/reports/documents, and local database canaries. Do not impersonate real users, query personal notes, read workspace secrets, capture live OAuth tokens, move/delete production assets, dump real CMS data, or run PHP gadget chains.
What changed¶
| Advisory | Component | Boundary | Operator value |
|---|---|---|---|
| GHSA-xqp3-jq6g-x3qm | File Browser proxy auth | Direct requests can supply the trusted proxy identity header when auth.method=proxy is enabled and the backend is network-reachable | Add direct-backend exposure and header-forgery checks to File Browser/reverse-proxy assessments. |
| GHSA-m93h-4hw7-5qcm | File Browser hook auth | Login-screen username/password values are expanded into an external shell hook command before authentication | Add hook-auth command-construction tests with inert credential canaries to File Browser reviews. |
| GHSA-hvr9-72v2-fff3 | SiYuan kernel auth | Any chrome-extension:// origin is treated as administrator for loopback APIs | Test local desktop app APIs for blanket browser-extension origin trust and missing extension-ID binding. |
| GHSA-gcm7-57gf-953c | SiYuan dynamic icon API | Unauthenticated icon rendering executes template helpers that can read SQLite note data when a valid block ID is supplied | Add unauthenticated render/template helper reachability checks with synthetic block IDs and marker tables. |
| GHSA-p4m3-mgmm-c664 | SiYuan publish /assets/*path | First-pass URL cleanup is followed by a fallback decode and publish access fall-through outside DataDir | Test double-encoding and route-specific patch gaps using only workspace canary files. |
| GHSA-w7cg-whh7-xp28 | SiYuan Bazaar README renderer | Markdown sanitizer blocks a legacy event-handler list but allows newer handler attributes before innerHTML insertion | Treat marketplace README/rendered-package metadata as trusted-origin DOM input; prove with harmless event markers. |
| GHSA-mvjr-vv3c-w4qv | SiYuan snippets | CSS snippet content can break out of a generated <style> tag and reach the Electron renderer | Test synced workspace configuration as a desktop-renderer trust boundary, without host command payloads. |
| GHSA-5xfx-xj4h-5p7r | SiYuan attribute-view cells | Synced database cell values in text, url, phone, and mAsset branches are interpolated into renderer HTML without escaping | Add attribute/database cell renderers to synced-workspace DOM-sink checks; stop at harmless renderer canaries unless a lab explicitly permits inert Electron sink validation. |
| GHSA-56mp-4f3v-fgj2 | SiYuan asset cells | Attribute View asset link names/content and tooltip aria-label round-trips reach innerHTML, including immediate page-load and hover-triggered sinks | Expand Attribute View tests to direct asset-cell page-load rendering and hover tooltip paths, not just text/url/phone branches. |
| GHSA-h29v-hj44-q8cv | Authorizer /authorize | redirect_uri is not validated against allowed origins before implicit-flow tokens are appended and redirected | Reuse OAuth redirect allowlist tests with owned callback URLs and fake lab tokens. |
| Pimcore advisory wave | Pimcore CMS/backend | WebDAV moves, report detail/export routes, class-definition import, translation filters, custom report SQL, and deserialization sources miss the expected auth/object/schema boundary | Add CMS route-family drift, object-permission, SQL-construction, and chained-deserialization precondition checks to Pimcore tests. |
Replayable validation boundaries¶
File Browser proxy-auth header forgery¶
- Confirm the deployment explicitly uses File Browser
auth.method=proxy; default JSON/password auth is a negative control. - Determine whether the File Browser backend is reachable directly, bypassing the trusted reverse proxy. Check only approved network paths and record listener address, security group/load-balancer path, and container port publishing.
- In a lab, send a request directly to the backend with the configured proxy username header, using a fake account such as
fb-canary-useror a disposable admin account. - Record whether File Browser accepts the header as identity or auto-creates the user. Evidence should be a role/session decision table, not access to real files.
- Add a negative control through the intended proxy path where the proxy strips client-supplied identity headers before setting its own value.
Report this as direct backend reachability -> caller-supplied proxy identity header -> File Browser session/user creation. Do not target production user names, shares, files, or admin actions.
File Browser hook-auth command construction¶
- Confirm hook authentication is enabled and identify the exact external command template. Default JSON/password auth is a negative control.
- In a disposable lab, submit login attempts where username and password contain inert shell metacharacter canaries that should be treated as data, not command syntax.
- Instrument the hook wrapper to log argv, environment, and marker-file side effects. Positive evidence is command substitution, extra shell tokens, or a marker generated before any successful authentication.
- Compare with a patched or safer configuration that passes credentials as fixed argv/environment values and rejects shell evaluation.
Report this as pre-auth login credential -> hook command expansion -> shell command boundary. Do not run reverse shells, destructive commands, or production hook binaries; keep evidence to inert marker strings and wrapper logs.
SiYuan browser-extension and loopback administrator boundary¶
- Use a disposable SiYuan desktop or Docker lab with synthetic notebooks and no personal workspace data.
- From a test Chromium extension you control, make one harmless API request to the loopback kernel and record the
Origin: chrome-extension://<id>value, response status, and reported role. - Test whether authorization binds to a specific extension ID, configured token,
AccessAuthCode, or browser profile. A blanket scheme allow is the vulnerable pattern. - Keep proof to route metadata or a synthetic configuration canary. Do not query note content, assets, sync keys, tokens, or browser history.
Report as browser extension origin -> blanket local API trust -> administrator role on loopback app. This is a local-service browser-pivot pattern; pair it with scoped extension and localhost reachability evidence.
SiYuan unauthenticated render helpers and publish path traversal¶
- Seed a lab workspace with one synthetic block ID and a marker row or note whose content is safe to disclose, for example
SIYUAN-CANARY-ONLY. - Exercise
/api/icon/getDynamicIconwith a template that queries only the seeded canary. Positive evidence is the canary in the SVG/response body without authentication. - For publish mode, place a harmless marker file under a lab workspace path that is outside
DataDirbut not sensitive. - Compare single-encoded, double-encoded, and patched route behavior on
/assets/*pathand any sibling routes that recently received traversal fixes. - Stop at marker files. Never request
conf, database, log, sync, token, or personal note files.
Report the boundaries separately: unauthenticated render endpoint -> template SQL helper -> note database canary, and double-encoded route parameter -> second decode fallback -> publish-mode outside-DataDir file read.
SiYuan marketplace README and snippet renderer DOM sinks¶
- For Bazaar README rendering, create a lab package or mocked marketplace response with harmless modern event-handler attributes such as pointer/focus/animation canaries.
- Open the package listing as a disposable administrator after the explicit marketplace trust step, and capture whether the rendered README is assigned into the main document without sandboxing.
- For snippet rendering, create a synced workspace snippet whose CSS body contains a harmless
</style>breakout marker that changes a local DOM marker only. - For attribute-view/database cells, seed a synced lab workspace with harmless values in
text,url,phone, andmAssetbranches that attempt only DOM marker insertion or a benignconsole.logcanary when the block-attribute panel opens. Include asset-cell link names/content that render immediately on page load andaria-labeltooltip values that render only after hover. - On desktop/Electron builds, do not use host-command payloads. The proof should stop at renderer script execution and pre/post DOM marker values unless the program explicitly approves an inert Electron sink such as writing to a temp canary file.
- Include controls where sanitization allowlists attributes, escapes
</style>, HTML-escapes cell values, uses a sandboxed iframe, or renders text inertly.
Report as untrusted marketplace/synced content -> trusted SiYuan origin DOM insertion -> renderer script canary. Keep host RCE discussion conditional unless an approved lab explicitly validates the Electron sink with inert commands.
Authorizer OAuth redirect URI token relay¶
- Create a disposable Authorizer lab with a fake client, fake user, and owned callback domain.
- Pull only public client metadata that the target intentionally exposes, then build
/authorizerequests forresponse_type=tokenorid_tokenwith an unregisteredredirect_uriunder your owned domain. - Authenticate as the disposable user and record only whether the 302
Locationpoints to the unregistered callback and contains fake token parameters. Redact token bodies or use throwaway tokens. - Test the expected negative controls: registered redirect succeeds, unregistered redirect is rejected, and other login/email flows that were previously fixed still call the allowlist validator.
Report this as public client ID -> unvalidated redirect_uri in /authorize -> implicit-flow tokens relayed to attacker-controlled origin. Do not target real users, harvest tokens, or send phishing links.
Pimcore CMS route, SQL, and deserialization drift¶
- Build a Pimcore lab with two backend users, seeded assets/documents/reports, and marker-only database rows.
- For WebDAV, test whether unauthenticated or low-privileged
MOVEcan move/delete/overwrite only disposable assets when normal asset permissions would deny it. - For CustomReports and WordExport, compare list visibility to direct detail/export routes using synthetic report/document IDs. Positive evidence is a hidden canary returned from a route whose listing correctly hid it.
- For class-definition import/save, translation grid filters, and custom report column configuration, keep SQL proofs to harmless syntax, error, or selected marker values. Do not dump user tables or credentials.
- Treat unsafe deserialization as a chain precondition. Show only that a seeded serialized canary reaches an
unserialize()source; do not run gadget chains or publish executable payloads.
Report the exact boundary: WebDAV route -> unauthenticated asset move, feature permission -> object export without view permission, report listing filter -> direct report detail bypass, class/report/filter metadata -> SQL expression construction, or writable CMS state -> unrestricted PHP deserialization sink.
October 1 follow-up: SiYuan publish-mode SQL injection and admin-layout disclosure (2 GHSAs)¶
GHSA-33jq-p8c2-q3q4 (critical): in publish mode, /api/filetree/searchDocs splices the caller-supplied keyword k straight into single-quoted LIKE literals across SearchDocs, NAMFilter (name/alias/memo branches, on by default), and QueryRootBlockByCondition — no escaping, no bind placeholders. The statement runs on a read-write SQLite handle through a driver that executes stacked ;-separated statements, against the global blocks table spanning every cleartext notebook. The route is gated only by CheckAuth, which the publish RoleReader token satisfies — and which is skipped entirely when Publish.Auth.Enable is false, making this unauthenticated. The only value-inspecting guard is ast.IsNodeIDPattern(), a shape check on a different input field. Proof with synthetic lab notebooks: one stacked SELECT reading a marker row from a second notebook, then a patched-commit (eef10568384e+) negative control; never target real user databases.
GHSA-hgfg-j9pg-43xw / CVE-2026-72788: POST /api/system/getConf is likewise reachable by the publish reader token (anonymously when auth is off) and returns Conf.UILayout through FilterConfByPublishIgnore — a walker whose four defects let an argument-less POST return the administrator's open password-protected document titles/IDs, locked/closed notebook contents, recent search terms with their scoped paths, and open private asset paths. Key asymmetry: the writer (setUILayout) is admin-gated, so the reader is replaying the admin's live workspace state, re-saved on every tab change. Restructuring the HideConfSecret blocklist path would not fix this — UILayout is a field intended to be served and filtered, and the filter's coverage is the bug.
Operator value: one reusable rule for publish/share modes in desktop-first apps — enumerate every API route the low-privilege reader token can hit, then check each response for admin-derived state (layout, recent items, drafts, search history) that the field-level filter was written to cover one known field at a time. Filters over allowlisted shapes fail open on every new field added to the payload; the stacked-statement SQLi additionally shows publish mode inherits the full read-write DB handle, so any string-concatenated query fragment behind the reader gate is a cross-notebook write primitive. Validation stays lab-only: disposable published instance, synthetic notebooks with marker rows/strings, reader-token route decision table (route, token, expected redaction, observed fields), owned-commit patched controls.
Reporting notes¶
- Lead with deployment preconditions: proxy-auth mode and direct backend reachability for File Browser; desktop/loopback, publish mode, valid block IDs, marketplace trust, or synced workspace write access for SiYuan; implicit-flow route exposure for Authorizer; authenticated backend role and feature permissions for Pimcore.
- Prefer decision tables over exploit prose: raw route, normalized route, role, expected denial, observed response, canary returned, and patched/negative control.
- Redact proxy usernames, OAuth tokens, workspace paths, block IDs tied to real notes, CMS object IDs, report names, database errors that reveal schema beyond the canary, and any host/container paths that identify tenants.
- Skip adjacent resource-only advisories from the same wave unless they unlock a non-availability operator workflow in scope.
October 2 follow-up: SiYuan publish-mode reader-scope leaks (3 GHSAs, 12:31Z wave, folded)¶
Three more publish-mode advisories (fixed in 3.8.5) extend the October 1 reader-token route-matrix rule with what the leak endpoints look like:
/api/export/previewreads protected database rows (CVE-2026-104410 / GHSA-84pg-x94v-x3xr, 7.5): request an export preview of a public document that embeds a database view, and password-protected / publish-disabled rows come back with primary-key text and cell values. The publish gate checked the document, not the embedded data source the document references — every embed/reference resolution is a second authorization decision that publish mode must make separately. Test: publish one disposable doc that embeds a protected attribute-view, then preview-export it as the reader.getNotebookInfoleaks hidden-document metadata (CVE-2026-103763 / GHSA-cj7w-46vh-93h9, 5.8, anonymous when no reader password): document count, size, and modification timestamps of publish-excluded documents in publish-visible notebooks. Existence/metadata of excluded items still flows through notebook-level endpoints.getRefCreateSavePath/getShorthandSavePath/getDocCreateSavePathreveal unpublished notebook internals (CVE-2026-103762 / GHSA-7234-66p2-jh2w, 5.3): POST any open notebook ID and receive the global save-box ID and save-path template for hidden notebooks — notebook existence and creation time disclosed via create-path helpers that were never meant to be publish-reachable. "Save path" and "where would this be created" endpoints leak structure because they're nominally write-support routes, not read routes; include them in the reader-token route sweep anyway.
Operator delta over the October 1 rule: the route sweep must include export/preview helpers and create-path/save-path utilities, not just read endpoints — reference resolution (embedded databases), notebook-level metadata aggregation, and path-template responses each made an independent leak surface inside the same reader gate.
October 2 22:3xZ follow-up: SiYuan publish-mode bulk handler sweep + admin WS proxy CSWSH (folded from the 22:3xZ wave)¶
- 17 of 28
/api/block/*handlers have zero publish-access filtering (GHSA-4vpg-gwqq-w44c / CVE-2026-74904, 7.5): the researcher's method is the lesson — automated extraction of every function body inkernel/api/block.go, grep for any of the three access-check symbols, cross-check against sibling functions in the same file that implement the check correctly. Result:getRefTextreturns the reference-display text (content-derived) for any block ID to anonymous publish-mode readers,checkBlockExist/checkBlocksExistare existence oracles,getBlockBreadcrumbleaks title paths, plus index/word-count/fold/sibling/annotation lookup endpoints — 17 handlers gated only byCheckAuthwith no publish check anywhere in the handler or its model functions. This extends the reader-token route sweep from export/preview helpers (Oct 2 fold above) to the whole file: when a feature gate exists in some handlers of a router file, the correct audit is a per-function symbol sweep of that file, not spot checks — uneven coverage is the norm. - Admin-only network-proxy WebSocket hard-codes
CheckOrigin: true(GHSA-3cc2-h3v6-rqpq / CVE-2026-74802, title CVSS low, advisory self-assessed high; unfixed at 3.7.3):/ws/network/proxyis an admin-role, fully attacker-specifiable forward proxy (base64 target URL + headers via query params) whose gorilla/websocket upgrader deliberately overrides the library's default origin check to always-true. WS handshakes carry ambient cookies and skip CORS preflight entirely → a malicious webpage gets an authenticated network pivot through the kernel process (loopback-bound desktop app = CSRF-through-the-user's-browser against a localhost-only service). Same day as the Headroom CSWSH leg on the Oct 2 AI page — durable pair: grep websocket upgraders forCheckOriginoverrides returningtrue, and treat any proxy/pivot route as CSWSH-grade regardless of its role gate, because the role gate travels on cookies the browser attaches anyway.
October 2 follow-up: SiYuan AI/MCP agent-plane gaps — rebinding TOCTOU + unbounded upload tool (2 GHSAs, folded)¶
The SiYuan advisory stream moved from the publish-mode reader plane to the AI agent/MCP tool plane (both incomplete-fix residuals of the earlier MCP/SSRF remediations, fixed 3.8.1):
- Agent
http_request/web_fetchSSRF via DNS-rebinding TOCTOU (GHSA-x8gv-g2g3-65fj, 8.2, ≤3.8.0): the SSRF gateCheckHostSSRFperforms one DNS resolution at guard time and rejects private/loopback/link-local answers — then the actual request connects through the default dialer, which performs a second, independent resolution with no connect-time check. Guard-answer public IP, connect-answer169.254.169.254. The remediation added both halves (CheckHostSSRFparse-time +SSRFSafeDialerconnect-time) but only wired the parse-time half into the agent tool paths — the main-vector fix exists in the same repo; the new tool surface just didn't call it. Operator rule: when a product ships a hardened dialer/socket helper, enumerate which fetch call sites actually use it; any guard that resolves DNS without pinning the answer to the connection (guard-time resolve + unpinned dial = TOCTOU by construction) is rebinding-testable with an owned short-TTL DNS fixture. This is the agent-tooling spelling of the classic rebinding pattern: prompt-injecting the agent is the delivery leg, and the advisory notes the tool's own docs document that scenario. - MCP
asset.uploadreads arbitrary absolute paths (GHSA-p23f-cm6q-2qp8, 5.7, ≤3.8.0): the tool'sfilesargument is a comma-separated list of absolute paths, normalized with onlyfilepath.Abs()— noIsSubPathworkspace check, noIsSensitivePathcheck — andInsertLocalAssetsos.Opens each and copies the bytes into the workspaceassets/directory, from where notes/export/sync can reach them. Every sibling file tool (file,unzip) resolves through the escape-proofresolvePath;asset.uploadis the one tool the MCP hardening pass (CVE-2026-66012, which addedCheckAdminRoleon/mcpandrefuseToAccessto the file tool) never touched. Operator rule: when auditing an agent tool registry, diff boundary-check symbol coverage per tool handler, not per server — the same per-function symbol sweep that found the 17/28block.gopublish gaps above applies tokernel/mcp/tools/: grep every tool handler for the workspace/sensitive-path predicates and treat any tool missing them as the residual. The copy-into-workspace sink is also the exfil pattern to hunt in any agent file tool: a tool that copies attacker-named files into an agent-readable/syncable location converts a local read into remote disclosure without any network egress from the host.
Validation stays lab-only: disposable SiYuan 3.8.0 build, owned domain with TTL-0/round-robin DNS answering public→loopback for the rebinding leg (prove with a synthetic canary served on lab loopback, never cloud metadata or third-party internals), and a temp canary file outside the workspace copied by a prompted asset.upload call; patched 3.8.1 controls on both legs.
October 5 follow-up: SiYuan path-guard residuals — blocklist content gaps + unguarded snapshot routes (2 GHSAs, folded)¶
The same util.IsForbiddenAbsPath() guard introduced by the GHSA-c8r8-95hg-mp34 remediation produced two more residuals in the Oct 5 17:32Z wave, each exposing a different failure dimension of a centralized deny-list:
- Deny-list content is a snapshot; key material generated at boot is not in it (GHSA-4wwp-f6gw-6qm5): the blocklist covers
conf/conf.jsonby exact match, butconf/key.pemandconf/ca.keysit in the same directory and were never added.POST /api/file/getFile {"path":"/conf/key.pem"}returns raw PEM private-key bytes — and on v3.8.1 every authenticated user receivesRoleAdministrator(no non-admin role is issued to direct API consumers), and on default no-auth-code instances no token is required at all. The files are generated on every boot even when TLS is inactive, so the secret exists on every installation. Impact chain:key.pem→ decrypt captured HTTPS traffic;ca.key→ mint certs trusted by clients that imported SiYuan's locally-generated CA. Third occurrence of this exact family (with GHSA-9jfx-rc58-h23j conf.json-via-template-render and GHSA-c8r8 MCP-tool blocklist). Operator rule: when a product's sensitive-file guard is a deny-list, enumerate the sibling files of each blocked path — directory listings, boot-time key/cert generation, and config writers add secrets the deny-list author never enumerated; and grep for role grants that make "authenticated" equal "administrator", because it silently downgrades every authenticated-user-reads-X advisory to unauthenticated-on-default-config. - Guard application missed sibling file-serving routes, and historical copies dodge the guard anyway (GHSA-3cm4-ccvw-6xr6, 4.9): the fix wired
IsForbiddenAbsPath()intokernel/api/file.goandkernel/mcp/tools/file.go— but/history/*pathand/repo/diff/*pathinkernel/server/serve.goalso serve arbitrary files by path, construct their target paths independently, and never call the guard. Because the history/repo tracked root isdata/, a prior snapshot ofdata/.siyuan/publishAccess.json(plaintext publish passwords) ordata/templates/*legitimately sits insideutil.HistoryDir/ the repo-diff checkout —/repo/diff/*path's own../IsSubPathchecks only confine you within the checkout, which is exactly where the protected file's historical copy lives. Two durable axes: (1) when a fix adds a centralized guard symbol, grep every route that serves files by path and check each call site — sibling routes that build paths independently are the residual (same per-call-site sweep as the 17/28block.gofinding above, applied to fix rollout instead of feature audit); (2) snapshot/history/backup/checkout directories are a bypass plane over any live-path protection — the guard protects where the file is, not where copies of it were; sweep history, diff, autosave, sync-temp, and backup endpoints for every recently-protected path.
Validation stays lab-only: disposable SiYuan instance, request conf/ sibling paths only on your own lab install (redact any real PEM material from evidence), seed then delete a synthetic publishAccess.json-style marker so a history snapshot exists, then fetch it via /history/ and /repo/diff/ with patched-version negative controls; never capture real user key material or publish passwords.
October 12 follow-up: SiYuan kernel plugin-response absolute-path read + uncapped Sprig function map in dynamic-icon endpoint (fixed 3.8.6)¶
- Plugin handler
ResponseFile.Pathreachesgin Context.Fileunvalidated (GHSA-g3cr-c99q-2hfc/CVE-2026-109309, medium): a kernel plugin (installable from the community marketplace) returns a file-serving response whosePathis used verbatim, so a malicious kernel plugin reading any file the SiYuan process can read — including the API token andconf.json— through the private plugin HTTP server. The boundary this page already documents for the server→filesystem direction now breaks in the plugin→server→response direction: plugin-supplied file paths are attacker-supplied file paths; confinement must be re-applied at the serving sink, not assumed at the handler. Supply-chain angle: marketplace plugins are the delivery vehicle, so the plugin surface is worth its own review pass on any SiYuan deployment in authorized scope. /api/icon/getDynamicIconcontent param passes an unrestricted Sprig template function map (GHSA-q79h-f459-w43f/CVE-2026-109310, high): uncapped helpers likeuntillet a publish reader (or anyone when publish auth is off) OOM-kill the kernel in one request. Template-engine resource rule: template params must run against an allow-listed, capped function map; Sprig's full map is a compute-DoS surface (until,repeatfamilies) even without RCE-capable funcs. One-request kernel death from the publish tier is also a availability signal for the publish-attack-surface inventory on this page.