OWASP ZAP Security Scan — MeshWeaver Production Portal (6 September 2026)

What this is — and is not. An internal, automated OWASP ZAP scan of the production portal, run by the MeshWeaver team on 6 September 2026 for the 3.0.0 release — a re-run of the 23 August 2026 scan of the same portal, so the two can be compared. It is not a third-party penetration test and is not presented as one; for contractual assurance Systemorph will commission, or support, an independent test on request. The dispositions below are as of the scan date; the current disposition of every rule is kept on OWASP ZAP Scan — Every Release under Findings by release.

Target https://memex.meshweaver.cloud (production portal)
Tool OWASP ZAP 2.17.0 (ghcr.io/zaproxy/zaproxy:stable) — zap-full-scan.py (full active) and zap-baseline.py -j (passive rules + AJAX spider)
Scan type Two passes: the public surface and the signed-in application. A full active attack scan of the public surface; an authenticated crawl performed as a real signed-in user (a genuine browser sign-in was captured and its session replayed on every request)
Date 2026-09-06 · active scan 05:40–06:20 UTC (40 min, 10-minute spider cap, 30-minute scan cap) · authenticated pass 05:40–05:52 UTC
Coverage Public active: 333 URLs, 136 rules passed, 0 failed, 5 warnings. Authenticated: 228 URLs, 58 rules passed, 0 failed, 9 warnings — up from 105 / 183 URLs in August

Executive summary

No exploitable vulnerability was found, anonymously or signed in. Every active-attack rule passed — 48 injection, scripting, execution, traversal, request-forgery and disclosure rules, listed below. The hardening headers fixed on 23 August are confirmed live on every route (verification below). The signed-in pass reached the pages a session unlocks (a user's Export page, the global settings) and surfaced no new vulnerability class: the same nine hygiene items as the anonymous run.

What is different from August is one sentence of honesty. The August report filed Vulnerable JS Library [10003] as "inside Monaco's own library". This run names it: the Monaco editor bundle carries DOMPurify 3.2.7, against which 2026 advisories exist (XSS via RAWTEXT elements in SAFE_FOR_XML, et al.). Third-party, editor-only, narrow — and not fixable by a package bump, because the newest BlazorMonaco release (3.5.0, the one pinned) still ships that bundle. It is tracked as MeshWeaver #3378 with the fix path (serve a current monaco-editor build in place of the bundled one). We would rather show a named, tracked item than a clean page with a footnote.

Delta against 23 August 2026

23 August 6 September Reads as
Public surface, active scan 105 URLs · 0 FAIL · 133 rules passed 333 URLs · 0 FAIL · 136 rules passed three times the surface, same result
Signed-in application, passive 183 URLs · 0 FAIL · 9 WARN · 58 PASS 228 URLs · 0 FAIL · 9 WARN · 58 PASS the same nine hygiene rules, no new class
Hardening headers (CSP, nosniff, CORP, COOP, Permissions-Policy, HSTS) fixed and verified still live on every route no regression
CORS posture no grant to a foreign origin unchanged (preflight now answers 404 rather than 405 — still no grant) no regression
Vulnerable JS Library [10003] noted as "Monaco's own library" DOMPurify 3.2.7 in the Monaco bundle, named; MeshWeaver #3378 open the one item with a real, narrow exposure
Backup File Disclosure [10095] false positive (SVG icon filenames) same false positive, 21 icons — housekeeping, see below not a defect

Attack classes tested — all passed

The active scan exercised the full OWASP injection and execution rule set against 333 URLs. Every one returned no alert:

(136 distinct passive and active rules passed on the public surface; 58 passive rules on the signed-in application.)

Findings — every warning, and what it is

Finding (ZAP rule) Where Severity Assessment (as of the scan)
Vulnerable JS Library (10003) — DOMPurify 3.2.7 inside editor.api-*.js of the Monaco editor signed-in pass, 1 asset Medium Real, narrow, tracked. Monaco uses DOMPurify to sanitise the markdown it renders inside the editor (hovers, suggestions); the exploit needs attacker-controlled content reaching that renderer on a page where a victim has the editor open. BlazorMonaco 3.5.0 — the newest release, the one pinned — still bundles monaco-editor 0.42.0-dev (2023) with DOMPurify 3.2.7; current monaco 0.56.0 carries DOMPurify 3.4.8. Fix: serve a current editor build in place of the bundled one — MeshWeaver #3378. Dependabot cannot see this one (static assets inside a NuGet package), which is exactly why a scan is run as well.
CSP: permissive directives (10055) — unsafe-inline / unsafe-eval on script-src, unsafe-inline on style-src, https: sources, form-action without fallback both passes, / and /login Medium Deliberate and documented, unchanged since August. Blazor Server emits inline script; the Monaco editor evaluates code at runtime; the product embeds customer content, media and third-party sign-in flows. Tightening means per-response nonces and enumerated origins — a separate, testable hardening pass, not a header edit. A complete policy IS returned on every route (10038 passes).
Backup File Disclosure (10095) 21 files under /static/NodeTypeIcons/ Medium False positive. Every hit is an SVG icon whose filename starts with Copy of / Copy (2) of — ZAP's rule matches the naming pattern of backup copies. They are stray duplicate icons, not backups of anything; the only follow-up is housekeeping (delete the duplicates).
Proxy Disclosure (40025) 305 responses Medium The managed ingress in front of the application announcing itself, working as intended.
Cross-Origin-Resource-Policy missing (90004) a handful of static assets: styles.css, fonts.css, favicon.ico, robots.txt, sitemap.xml Low HTML and API routes carry same-site (verified below); the static-files path does not add it. Low value, low risk — a hardening follow-up.
Cross-Origin-Embedder-Policy missing (90004) /, /login, /sitemap.xml Low Deferred by decision, as in August: require-corp breaks cross-origin embeds and worker loading.
Dangerous JS Functions (10110) — eval( Monaco loader.js Low Inside the Monaco editor's own loader (third-party).
Timestamp disclosure (10096), suspicious comments (10027), Modern Web Application (10109), cache-control (10015 / 10049), cookie slack (90027), session-management response (10112), user-agent fuzzer (10104), information in localStorage (120000) various Informational Hygiene and fingerprinting notes; nothing exploitable. The localStorage item is the signed-in UI remembering its own state on two pages.

Live header verification (6 September 2026, curl)

Every route returns the complete hardening set — the state the 23 August fixes left the portal in:

Route CSP (complete policy) X-Content-Type-Options: nosniff Cross-Origin-Resource-Policy: same-site Cross-Origin-Opener-Policy: same-origin Permissions-Policy HSTS (1 year, subdomains)
/
/Store
/app
/login
/api/version
content-security-policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self';
    img-src 'self' data: blob: https:; media-src 'self' data: blob: https:; font-src 'self' data: https:;
    style-src 'self' 'unsafe-inline' https:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:;
    worker-src 'self' blob:; connect-src 'self' https: wss:; frame-src 'self' https:; form-action 'self' https:
x-content-type-options: nosniff
cross-origin-resource-policy: same-site
cross-origin-opener-policy: same-origin
permissions-policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(),
    microphone=(), payment=(), usb=()
strict-transport-security: max-age=31536000; includeSubDomains

Cross-site / CORS posture — unchanged

  1. Same origin, no CORS surface: the SPA, the portal and /api share one origin.
  2. No CORS grant to a foreign origin (re-verified 6 September): a request carrying Origin: https://evil.example receives no Access-Control-Allow-Origin header, and a cross-origin preflight OPTIONS is refused (404) — a malicious page's JavaScript cannot read any API response.
  3. SameSite=Lax session + Bearer-only writes: the session cookie is not sent on a cross-site POST, and every mutating API/MCP verb requires a Bearer token — CSRF surface zero by construction.

Limitations (stated plainly)

Appendix — raw scan output (OWASP ZAP 2.17.0, 6 September 2026)

== Public surface — zap-full-scan.py (active) — https://memex.meshweaver.cloud — 2026-09-06 05:40–06:20 UTC
Total of 333 URLs
WARN-NEW: CSP: Failure to Define Directive with No Fallback [10055] x 15
WARN-NEW: Backup File Disclosure [10095] x 21                    (21 SVG icons named "Copy of …" — false positive)
WARN-NEW: Dangerous JS Functions [10110] x 1                     (Monaco loader.js)
WARN-NEW: Proxy Disclosure [40025] x 305                         (managed ingress — expected)
WARN-NEW: Cross-Origin-Resource-Policy Header Missing or Invalid [90004] x 14   (static assets only)
FAIL-NEW: 0  FAIL-INPROG: 0  WARN-NEW: 5  WARN-INPROG: 0  INFO: 0  IGNORE: 0  PASS: 136

== Signed-in application — zap-baseline.py -j (passive + AJAX spider, captured session replayed) — 2026-09-06 05:40–05:52 UTC
Total of 228 URLs
WARN-NEW: Vulnerable JS Library [10003] x 1                      (DOMPurify 3.2.7 inside the Monaco editor bundle — MeshWeaver #3378)
WARN-NEW: Re-examine Cache-control Directives [10015] x 5
WARN-NEW: Information Disclosure - Suspicious Comments [10027] x 15
WARN-NEW: Non-Storable Content [10049] x 11
WARN-NEW: CSP: Failure to Define Directive with No Fallback [10055] x 10
WARN-NEW: Timestamp Disclosure - Unix [10096] x 3
WARN-NEW: Modern Web Application [10109] x 5
WARN-NEW: Dangerous JS Functions [10110] x 1
WARN-NEW: Cross-Origin-Embedder-Policy Header Missing or Invalid [90004] x 7
FAIL-NEW: 0  FAIL-INPROG: 0  WARN-NEW: 9  WARN-INPROG: 0  INFO: 0  IGNORE: 0  PASS: 58

== Active-attack rules exercised on the public surface — every one PASS (no alert)
  Cross-Domain JavaScript Source File Inclusion [10017]
  HTTP Parameter Override [10026]
  Off-site Redirect [10028]
  Big Redirect Detected [10044]
  Source Code Disclosure - /WEB-INF Folder [10045]
  Remote Code Execution - Shell Shock [10048]
  Source Code Disclosure [10099]
  HTTP Parameter Pollution [20014]
  Source Code Disclosure - CVE-2012-1823 [20017]
  Remote Code Execution - CVE-2012-1823 [20018]
  External Redirect [20019]
  Buffer Overflow [30001]
  Format String Error [30002]
  Integer Overflow Error [30003]
  CRLF Injection [40003]
  Parameter Tampering [40008]
  Cross Site Scripting (Reflected) [40012]
  Cross Site Scripting (Persistent) [40014]
  Cross Site Scripting (Persistent) - Prime [40016]
  Cross Site Scripting (Persistent) - Spider [40017]
  SQL Injection [40018]
  SQL Injection - MySQL (Time Based) [40019]
  SQL Injection - Hypersonic SQL (Time Based) [40020]
  SQL Injection - Oracle (Time Based) [40021]
  SQL Injection - PostgreSQL (Time Based) [40022]
  Cross Site Scripting (DOM Based) [40026]
  SQL Injection - MsSQL (Time Based) [40027]
  NoSQL Injection - MongoDB [40033]
  Log4Shell [40043]
  Spring4Shell [40045]
  Server Side Request Forgery [40046]
  Text4shell (CVE-2022-42889) [40047]
  Remote Code Execution (React2Shell) [40048]
  Source Code Disclosure - Git [41]
  Source Code Disclosure - SVN [42]
  Source Code Disclosure - File Inclusion [43]
  Path Traversal [6]
  Remote File Inclusion [7]
  XSLT Injection [90017]
  Server Side Code Injection [90019]
  Remote OS Command Injection [90020]
  XPath Injection [90021]
  Expression Language Injection [90025]
  SOAP XML Injection [90029]
  Server Side Template Injection [90035]
  Server Side Template Injection (Blind) [90036]
  Remote OS Command Injection (Time Based) [90037]
  NoSQL Injection - MongoDB (Time Based) [90039]

The full HTML, Markdown and JSON reports of both passes (about 3 MB) are kept by Systemorph — they are a site map with response bodies and never enter a repository — and are available to a customer's security team on request.

Run and written by Systemorph, 6 September 2026 · the captured session used for the authenticated pass was discarded after the run.

Reconnecting…
The server was updated. Reloading the page to pick up the latest version.