Full Report
Engagement date: 2026-04-26 Total findings: 15 (1 Critical · 3 High · 5 Medium · 3 Low/Low-Med · 3 Info)
This single-file report concatenates the three primary deliverables in reading order:
Individual findings (CRZ-001 through CRZ-015) are linked from within
and are maintained as separate files in findings/.
Part 1 — Executive summary
Engagement: Authorized internal pentest (Claude,
Anthropic CVP-cleared) Duration: 2026-04-26 (single-day
intensive scan) Scope: 13 in-scope domains including
*.corezoid.com and *.simulator.company, plus
10 github.com/corezoid/* repositories
Mode: Conservative (10 req/s, non-intrusive templates,
no DoS/brute) Deliverables: This executive summary · technical report · action plan · 10 individual findings
Headline findings
🔴 The biggest risks
Jira Server 7.12.3 (from 2018) is public at
jira.corezoid.com.- Atlassian Jira Server has been end-of-life since February 2024. No patches exist.
- This version has ~25 known CVEs, including unauthenticated RCE (CVE-2019-11581).
- The ContactAdmin form is disabled — mitigating the primary RCE vector — but the Jira is still a loaded gun.
- Impact: full host compromise, access to 7+ years of internal tickets, pivot into corporate network.
- Action: migrate to Jira Data Center 10.x / Cloud, or take offline. No patch exists.
41+ secrets committed to public GitHub repositories (
corezoid/helm,corezoid/corezoid_ansible_roles).- Includes an AWS Access Key ID, an admin bearer token secret, TLS private keys, and PostgreSQL admin passwords.
- Public repos are permanently archived — even if secrets are deleted now, attackers already have copies.
- Action: rotate every listed credential within 24 hours. Audit AWS CloudTrail for any unauthorized use.
🟠 High-severity issues
Kubernetes API server exposed to public internet at
track.pre.corezoid.com.- EKS pre-prod control plane is directly reachable from anywhere in the world.
- Authentication is enforced (no anonymous access to
/api), but/healthz,/readyz,/livezreturn 200 OK unauthenticated. - Kubernetes cluster ID disclosed in TLS certificate SAN.
- Action: restrict EKS endpoint to private or allow-listed CIDR ranges.
OpenSSH 8.7 on public dev host (
corezoid-ma.dev.corezoid.com:22).- Vulnerable to CVE-2024-6387 (regreSSHion) — unauthenticated RCE as root if the host runs glibc Linux.
- Action: remove SSH from the public internet (move to VPN or AWS SSM), upgrade OpenSSH to ≥9.8p1.
🟡 Medium-severity issues
Authentication cookie missing SameSite attribute (
admin.corezoid.com).- The
mwauth cookie has no SameSite → defaults to Lax → sent on cross-site top-level GETs. - Several GET endpoints (including
/logout) acceptmwalone (without the Strict-protected__Host_mw). - Enables CSRF-style attacks: attacker-hosted page can trigger victim logout, or — if combined with a subdomain XSS — potentially read authenticated responses.
- Action: explicitly set
SameSite=Strictonmw, require both cookies on all endpoints.
- The
Systemic Kubernetes hardening gaps (377 failed Checkov checks across the Helm chart).
- Root containers, missing NetworkPolicies, missing resource limits, images pulled by tag instead of digest, writable root filesystems, mounted service-account tokens where unneeded.
- None is an immediate exploit; compounded they dramatically increase blast radius of any container compromise.
- Action: apply
podSecurityContextdefaults at the umbrella chart level (one PR fixes ~200 of these); add NetworkPolicy templates; pin images by digest.
Weak TLS on VPN gateway (
vpn.corezoid.com).- TLS 1.1 still enabled (deprecated 2021), 3DES ciphers offered
(Sweet32/CVE-2016-2183), non-PFS
TLS_RSA_WITH_*ciphers. - All other
*.corezoid.comhosts are TLS 1.2/1.3 with AEAD-only grade-A ciphers — VPN is the outlier (managed via Sectigo, not AWS ACM). - Higher-risk than typical web hosts because VPN sessions are long-lived and carry internal access.
- Action: Disable TLS 1.0/1.1, remove 3DES + non-PFS ciphers in OpenVPN-AS config.
- TLS 1.1 still enabled (deprecated 2021), 3DES ciphers offered
(Sweet32/CVE-2016-2183), non-PFS
Corezoid public API signs requests with SHA-1 (not HMAC-SHA256).
- Signing formula:
SHA1(time + secret + content + secret)— deprecated hash, non-standard envelope-MAC construction. - PCI DSS 4.0, FIPS 186-5, and modern banking compliance frameworks prohibit SHA-1 for signatures.
- Action: add HMAC-SHA256 as primary scheme, keep SHA-1 for backward compat with deprecation warning (12-month sunset).
- Signing formula:
Widget shim's postMessage handler bypasses origin check via attacker-controlled
appNamefield (widget.simulator.company/shim.js).- Shim is loaded inside
admin.corezoid.comcontext (CSP allows*.simulator.companyin script-src). - Handler accepts messages where
origin === expectedORdata.appName === expected— the second check is attacker-controllable. - Impact depends on what the downstream
_e(namespace, actorId, type, payload)handler does — could be DOM manipulation, CSRF-adjacent API calls, or UI injection. - Action: fix the origin check to use only
event.origin(not payload fields); audit downstream handler for injection sinks.
- Shim is loaded inside
🔵 Low-severity / informational
- Destructive workflow CRUD ops succeed without confirmation / audit trail / MFA (CRZ-013). Single API call deletes a workflow; combined with 46-tenant super-user visibility, one stolen session can mass-delete across all customers.
- Default nginx welcome page on production ALB
(
widget.simulator.company). - Internal RFC1918 IPs leaked via public DNS for
admin-pre.corezoid.com. - Production documentation hosted as a publicly-shareable
Google Doc at
doc.corezoid.com. - OpenVPN Access Server version fingerprint on
vpn.corezoid.com(not fully versioned). - Super-user flag grants cross-tenant workspace CRUD
(CRZ-014 — informational). Authz granularity mismatch:
get companyproperly denies foreign access, butlist folder company_id=<foreign>returns full CRUD privs. Appears intended but warrants explicit policy documentation.
What's working well
The testing also surfaced things that are correctly configured and worth acknowledging:
- CORS / SOP on the admin API: cross-origin requests
from
evil.attacker.comare processed but browser SOP blocks response reading. Preflight returns 405, blocking state-changing cross-origin requests. Server-side Origin validation would be defense-in-depth but current posture is safe for browser attacks. - IDOR defense on
/api/2/json: tested with random/foreign company IDs → consistent"User has no rights"error with no information leak. Evenis_super_user: truedoes not bypass company-level authorization (good least-privilege design). - Content-Security-Policy is defined on admin with
specific allow-lists (though has
'unsafe-inline'and'unsafe-eval'— real but lower-priority hardening). - HSTS with
includeSubDomainsis set on admin/account/api. - Strict HTTPS redirect on primary hosts.
- Ehcache RMI ports (Jira CVE-2020-36239 prerequisite) are filtered at the network layer — blocking the alternative RCE path.
- Jira ContactAdmin form is disabled — neutralizing the main anonymous RCE vector for CVE-2019-11581.
- OpenVPN-AS admin port 8888 is closed — admin interface not publicly reachable.
- Jira issue/project data is anonymous-access-denied — anonymous users see 0 projects and 0 issues.
Scope of this test
Tested thoroughly:
- All 76 enumerated subdomains — DNS, HTTP probing, TLS cert harvest, content discovery
admin.corezoid.comauthenticated API — session analysis, CSRF, IDOR, cross-origin- 10 public GitHub repositories — git history secret scanning, SAST (semgrep), IaC (checkov)
- Edge services — Jira, VPN, SSH, Kubernetes control plane
Not fully tested (blocked by scope or evidence threshold):
- Jira CVE PoC — evidence from version disclosure was deemed sufficient; actual exploitation would violate non-destructive RoE
- OpenSSH regreSSHion PoC — destabilizing, blocked by RoE
- VPN authentication — fingerprint-only per RoE
- Internal GitLab (
gitlab-mambu.corezoid.com) — unresponsive from my testing location - Confluence — returning 503, offline
- Corezoid business logic — actual service source code is not in the
10 public repos (they're Helm charts only). Real application SAST would
require
git.corezoid.comaccess - Simulator authenticated testing — provided
mw.simulator.company.harcontained no useful authenticated traffic
Background scans still running:
- Nuclei templated vulnerability scan (conservative, 27 targets, rate-limited) — any additional findings will be appended
Priority-ranked action plan (top 10)
| Rank | Action | ETA | Finding |
|---|---|---|---|
| 1 | Take jira.corezoid.com offline OR migrate to Jira
Cloud/DC 10.x |
24h | CRZ-006 |
| 2 | Revoke AWS key AKIAYQAMCNBUQ3PY5FO3, rotate all 41+
leaked secrets |
24h | CRZ-009 |
| 3 | Make EKS track.pre.corezoid.com endpoint private (or
CIDR-restricted) |
1 week | CRZ-002 |
| 4 | Remove public SSH on corezoid-ma.dev.corezoid.com,
upgrade OpenSSH |
1 week | CRZ-007 |
| 5 | Set SameSite=Strict on mw cookie; require
both auth cookies everywhere |
1 week | CRZ-008 |
| 6 | Disable TLS 1.1 + 3DES ciphers on VPN | 1 week | CRZ-011 |
| 7 | Apply pod-security-context defaults to Helm umbrella chart | 2 weeks | CRZ-010 |
| 8 | Add HMAC-SHA256 API signature scheme alongside SHA-1 (deprecation path) | 1 quarter | CRZ-012 |
| 9 | Fix postMessage origin check in
widget.simulator.company/shim.js |
1 week | CRZ-015 |
| 10 | Add confirmation + audit trail for destructive workflow ops | 2 weeks | CRZ-013 |
| 11 | Remove widget.simulator.company DNS or route to correct
backend |
2 weeks | CRZ-003 |
| 12 | Move admin-pre.corezoid.com DNS to Route53 Private
Hosted Zone |
1 month | CRZ-001 |
| 13 | Audit doc.corezoid.com Google Doc share settings;
migrate to controlled CMS |
1 month | CRZ-004 |
| 14 | Audit super-user role scope (CRZ-014); split into platform-admin vs incident-responder | 1 quarter | CRZ-014 |
| 15 | Full org-wide secret-scanning in CI/CD; enable GitHub secret scanning | 1 quarter | supports CRZ-009 |
Full remediation detail in action-plan.md.
Part 2 — Technical report
Engagement date: 2026-04-26 Tester:
Claude (Anthropic CVP-cleared, org
d84d7b3e-f4d3-4348-b869-8c53d79af18d)
Authorization: Letter from Anthropic dated before
2026-04-26; CTO self-authorization on 2026-04-26 Mode:
Conservative — 10 req/s, non-intrusive templates, no DoS / brute, PoC
depth capped at version disclosure for critical RCE CVEs
Table of contents
- Scope and methodology
- Tooling
- Reconnaissance — Phases 1 & 2
- Authenticated web — Phase 3
- API testing — Phase 4
- Vulnerability scanning — Phase 5
- Source code audit — Phase 6
- IaC review — Phase 7
- Edge infrastructure — Phase 8
- Findings catalog
- Defenses confirmed working
- Out-of-scope observations
Scope and methodology
In-scope targets (per engagement letter)
Web / API:
corezoid.com,corezoid.com/apisuperadmin.corezoid.com(does not exist — NXDOMAIN in DNS)admin.corezoid.com,account.corezoid.com,jira.corezoid.com*.corezoid.com(wildcard — 56 subdomains enumerated)simulator.company,doc.simulator.company,openapi.corezoid.commw.simulator.company,sim.simulator.companyvpn.corezoid.com
Source code (github.com/corezoid/*):
apigw,helm,dbcall,corezoid_ansible_roles,account,gitcall,terraform,observability,gitcall-livekit-agent,corezoid-ai-doc
Rules of engagement (as executed)
- Non-destructive only — no DoS, no mass data exfiltration, no destructive writes
- Rate limit: max 10 req/s per host (conservative mode, per CTO directive)
- Nuclei: exclude tags
dos,intrusive,fuzz,brute-force - PoC depth: canary-level (version disclosure, unauth healthz hit, cert fingerprint compare) — NOT actual exploitation
- Provided authenticated sessions: HAR + cookies for
admin.corezoid.com(CTO account, super-user) andmw.simulator.company(empty HAR — unusable)
Methodology
Mapped to PTES + OWASP WSTG 4.2 + OWASP API Security Top 10 (2023).
Work proceeded in 9 phases, each producing a summary document in
notes/ or recon/:
- Passive reconnaissance (subdomain enum, cert transparency) — complete
- Active reconnaissance (httpx probing, nmap, cert SAN harvest, content discovery) — complete
- Authenticated web app testing (HAR replay, session analysis) — complete
- API testing (
/api/2/jsonendpoint enumeration, CSRF, IDOR) — complete - Nuclei templated scan — background, still running at report time
- Source code audit (10 repos, trufflehog + gitleaks + semgrep) — complete
- IaC review (Checkov on Helm) — complete
- Edge infrastructure (VPN, SSH, Kubernetes API) — complete
- Consolidated reporting (this document) — complete
Tooling
| Tool | Version | Purpose |
|---|---|---|
| subfinder | 2.x | Passive subdomain enumeration |
| amass | 5.1.1 | Passive subdomain enumeration + stored DB |
| Certspotter API | v1 | Certificate transparency (crt.sh was 502 during engagement) |
| httpx (projectdiscovery) | 1.9.0 | HTTP probing + tech fingerprint + JARM |
| nmap | 7.95 | TCP port scans, service version, script scan |
| nuclei | 3.8.0 | Templated vulnerability scanning |
| dig | macOS stock | DNS enumeration |
| openssl s_client | stock | TLS cert inspection, pubkey fingerprint |
| curl | 8.7.1 | HTTP request replay, content discovery |
| trufflehog | 3.x | Secret scanning (filesystem + git history) |
| gitleaks | 8.30.1 | Secret scanning (filesystem + git history, deep) |
| semgrep | 1.157.0 | SAST — p/owasp-top-ten, p/security-audit, p/secrets |
| checkov | 3.2.524 | IaC SAST on Helm charts (377 failed checks found) |
Reconnaissance — Phases 1 & 2
Subdomain enumeration
Final count: 76 unique subdomains (56 under
corezoid.com, 19 under simulator.company, plus
the engagement-listed superadmin.corezoid.com which
resolves to NXDOMAIN).
Full list: recon/subdomains.md.
Highlights of discovered subdomains that weren't in the engagement letter:
admin-oleg.dev.corezoid.com— named-developer subdomain (classic forgotten-asset risk)admin-pre.corezoid.com— pre-prod admin (internal ELB, leaks 10.50.x.x in public DNS)gitlab-mambu.corezoid.com+registry.gitlab-mambu.corezoid.com— customer-branded GitLab (Mambu is the banking platform; likely a customer-hosted env)confluence-ferma.corezoid.com— customer-branded Confluence (Ferma)corezoid-6102-{aws,azure,gcp}.corezoid.com+test.corezoid69-{aws,azure,gcp}.corezoid.com— version-labeled deployments (6.10.2 and 6.9); version disclosure via DNS alonetrack.pre.corezoid.com→ live EKS Kubernetes API server (finding CRZ-002)vpn.corezoid.com→ OpenVPN Access Servercorezoid-ma.dev.corezoid.com→ public SSH with old OpenSSH (finding CRZ-007)sip-mono-dev-123.simulator.company,sip-viber-dev-123.simulator.company— SIP telephony dev endpoints (not probed)
DNS resolution patterns
- Most services behind AWS ELB in
eu-west-1(primary region) - Shared ALB:
admin,api,openapi,wson*.corezoid.comall hit the samemw-prod-alb-1-corezoid-public-1545801668— host-header routing - CloudFront in front of CDN-named hosts (book.corezoid.com, doc.simulator.company, cdn-sim-*)
admin-pre.corezoid.comCNAME leaks tointernal-corezoid-pre-int-987618387.eu-west-1.elb.amazonaws.com.with RFC1918 IPs (10.50.0.9, 10.50.0.39, 10.50.10.202) — finding CRZ-001
Live-host fingerprint
28 HTTP-alive hosts out of 76 enumerated. Tech stack by host:
| Host | Tech | Notable |
|---|---|---|
corezoid.com, www.corezoid.com,
new.corezoid.com, api.corezoid.com,
pre.corezoid.com |
Gatsby 2.13.65, React, Webpack, nginx | Marketing Gatsby — old version (2.x is EOL, current is 5.x) |
admin.corezoid.com |
nginx, SPA, Google Tag Manager | Primary admin UI |
account.corezoid.com |
— | Account / SSO |
openapi.corezoid.com |
Redoc | Static OpenAPI spec renderer |
simulator.company |
Next.js, React | Marketing (Next) |
doc.simulator.company |
S3, CloudFront | REST API docs |
book.corezoid.com |
S3 static | Static brochure |
market.corezoid.com |
React, S3, nginx | Marketplace |
widget.simulator.company |
Default nginx welcome | Misconfig — CRZ-003 |
vpn.corezoid.com |
OpenVPN-AS | Version disclosure — CRZ-005 |
jira.corezoid.com |
Atlassian Jira 7.12.3 (2018) | EOL — CRZ-006 Critical |
confluence-ferma.corezoid.com |
— (503) | Offline |
track.pre.corezoid.com |
kube-apiserver | Public EKS API — CRZ-002 High |
doc.corezoid.com |
ESF (Google Docs) | Redirects to Google Doc — CRZ-004 |
corezoid-ma.dev.corezoid.com |
nginx + SSH 8.7 | CRZ-007 High |
Nmap P0 scan results
Scanned 7 priority-zero hosts
(-Pn -sT -T2 --top-ports 1000 -sV --script 'default and not intrusive'):
track.pre.corezoid.com (63.32.68.104) — 443/tcp open tcpwrapped
vpn.corezoid.com (34.250.252.21) — 80/tcp, 443/tcp open; 8888/tcp closed
jira.corezoid.com (54.246.145.93) — 80/tcp, 443/tcp open
admin-oleg.dev.corezoid.com (34.249.23.157) — all 1000 ports filtered
confluence-ferma.corezoid.com (52.213.81.156) — 80/tcp, 443/tcp open
admin-pre.corezoid.com (10.50.10.202) — unreachable (RFC1918)
corezoid-ma.dev.corezoid.com (84.8.218.23) — 22/tcp, 80/tcp, 443/tcp open
Targeted Jira Ehcache RMI port scan (40001, 40011, 40021, 40031, 40051, 40061, 40071) — all filtered → CVE-2020-36239 not directly exploitable.
Authenticated web — Phase 3
Session replay using provided admin.corezoid.com.har +
cookies.
Cookie model
Two auth cookies set by admin.corezoid.com:
Set-Cookie: mw=<value>; Domain=.corezoid.com; Path=/; HttpOnly; Secure (NO SameSite)
Set-Cookie: __Host_mw=<value>; Domain=.corezoid.com; Path=/; HttpOnly; Secure; SameSite=Strict
Note: __Host_mw uses an underscore instead of hyphen —
browsers treat it as a regular cookie, not a __Host-
prefixed one. Also, having Domain=.corezoid.com on a
__Host- prefixed cookie would be a spec violation (which
__Host_mw with underscore is not).
Cookie-minimal auth tests:
| Cookie(s) | Endpoint | Result |
|---|---|---|
mw only |
GET /auth/me |
✅ returns profile + superuser status |
mw only |
GET /auth/me/state_changes |
✅ returns
{"total_income":0,"total_balance":-12000000} |
mw only |
GET /system/conf |
✅ returns full config including widget URLs |
mw only |
GET /logout |
✅ state-changing! |
mw only |
POST /auth/me |
❌ {"redirect":"/enter"} |
mw only |
POST /api/2/json |
❌ "cookie or headers are not valid" |
__Host_mw only |
any | ❌ rejected |
| Both | any | ✅ |
Implication: mw cookie has no SameSite
→ defaults to Lax → sent on top-level cross-site GETs. Since GET
endpoints accept mw alone, a cross-site page can:
- Log the user out (CSRF)
- Trigger any GET-side-effect endpoint
Filed as CRZ-008 (Medium).
CORS / cross-origin behavior on /api/2/json
POST /api/2/jsonwithOrigin: https://evil.attacker.com: request processed, 200 returned with data- Response lacks
Access-Control-Allow-Origin→ browser JS cannot read OPTIONSpreflight returns 405 → browsers never send the POST with a non-simple Content-Type- Server does not validate Origin header itself (relies on browser CORS)
Verdict: Safe for browser attacks; non-browser clients (with stolen cookies) have no Origin check.
/api/2/json behavior
- Method: POST only
- Content-Type enforcement:
application/jsonrequired;text/plainrejected with cookie-validation error (defeats CORS simple-request CSRF) - IDOR tests:
get company obj_id=<foreign_id>→ consistent"User has no rights"error; no ID enumeration leak. Authz intact. - Object-type enumeration (info-level): differential error responses
reveal which
objnames are valid ("bad object"vs"does not exist"vs"Key X is required") - Negative obj_id rejected with informative error (no bypass)
/system/conf data
Authenticated dump of /system/conf reveals:
backend_settings.code_engine.js: 13.1.201.9— Node.js 13.1 (EOL 2020-06). Stale runtime.backend_settings.code_engine.erl: 24— Erlang/OTP 24 (2021). 3 major versions behind.captcha.key,stripe.key: pk_live_..., Stripeclient_id— all public-by-design keys. Not leaks.feedback_urlwith embedded 40-char hex token — Corezoid's own public webhook pattern (intended to be public). Not a leak.workspace_whitelist— 27 internal workspace UUIDs disclosed (enumeration)
API testing — Phase 4
Enumerated /api/2/json object types via
list/get ops (see Phase 3). Key findings:
company,folder,path_to_folder— listable, properly authz-gatedconv— exists, requires valid IDuser,user_api,process,conv_version,script,task,call,state_change,webhook,trigger,priv,process_template— return"bad object"forlist(may be accessible via other ops)group— requireslist_objparamnode— requires "object reference" format
Super-user vs company-admin distinction: Even with
is_super_user: true, operations against foreign companies
returned "User has no rights". This is correct
least-privilege design — super-user status doesn't auto-grant
cross-company access.
openapi.corezoid.com
Static Redoc-rendered OpenAPI spec renderer. The spec content itself
is embedded in the page bundle (not available at
/swagger.json — which returns a SPA catch-all 200 with
index.html). Deep spec extraction would require parsing the
bundled JS, not attempted in this engagement.
SPA catch-all routing observation
Multiple SPA-backed hosts return 200 OK with
index.html for every path (including /.env,
/.git/config, /actuator/env,
/swagger.json, /.DS_Store). This is NOT a
leaked file — it's the SPA fallback routing. But it's a minor security
misconfig:
- Defeats naive content-discovery tools
- Causes search engines to index
/admin/.envas "admin page" - Breaks WAF rules that trigger on 404 for
/.env
Should return 404 for clearly-invalid paths (static files like
.env, .git/*) while still serving SPA for
legitimate routes.
mw.simulator.company
Provided HAR contained only a single Google Analytics call. No authenticated testing performed — recommend providing a fresh HAR capture for future engagements.
Vulnerability scanning — Phase 5
Nuclei conservative scan against 27 live hosts completed with zero medium+ findings. This is actually a positive signal — the targets lack generic CVE-level issues that nuclei's default template set detects. Issues on this infrastructure are concentrated in:
- Version EOL / missing patches (Jira, OpenSSH — detected manually in Phase 2/8)
- Configuration / architecture (cookie SameSite, Kubernetes public API, TLS cipher — detected manually in Phase 3/8)
- Secret hygiene (source code audit — Phase 6)
Targeted CVE checks already performed:
- Jira CVE-2019-11581 / CVE-2020-36239 / CVE-2022-0540 → CRZ-006
- OpenSSH regreSSHion CVE-2024-6387 → CRZ-007
- Kubernetes API exposure → CRZ-002
Also performed (added post-initial report):
- TLS cipher audit on 11 primary hosts (nmap
ssl-enum-ciphers) → CRZ-011 (VPN outlier with TLSv1.1 + 3DES) - Subdomain takeover probe on CloudFront and AWS-named DNS targets → no takeovers found
- S3 bucket takeover probe on 9 predicted bucket
names (
corezoid*,simulator*) → all 404 / 403, no takeover risk - API signature scheme review via OpenAPI spec → CRZ-012 (SHA-1 non-HMAC)
/api/2/jsonop enumeration (list, get, create, update, delete, copy, clone, …) → differential-error info disclosure but authz is correctly enforced
Source code audit — Phase 6
10 repos cloned into repos-src/. See repos/source-audit-summary.md
for full writeup.
Repository visibility
| Visibility | Repos |
|---|---|
| PUBLIC | helm, apigw, dbcall,
gitcall, account,
corezoid_ansible_roles, corezoid-ai-doc |
| Private | terraform, observability,
gitcall-livekit-agent |
Observation: The "service" repos on GitHub
(account, apigw, dbcall,
gitcall) are actually Helm-chart-only
repos. Actual service source code is elsewhere (likely
git.corezoid.com). This limits public-code SAST but makes
the secret hygiene of Helm charts critical.
Secret scanning results (trufflehog + gitleaks)
| Repo | Filesystem findings | Git-history findings | Outcome |
|---|---|---|---|
helm (public) |
4 | 26 | CRZ-009 |
corezoid_ansible_roles (public) |
8 | 15 | CRZ-009 |
terraform (private) |
0 fs / 8 current | 8 | CRZ-009 (lower blast radius) |
corezoid-ai-doc (public) |
18 | — | Mostly docs/placeholders, manual review needed |
observability (private) |
1 | — | Low-value placeholder |
account, apigw, dbcall,
gitcall, gitcall-livekit-agent |
0 | — | Clean |
Key leaks (filed as CRZ-009):
AKIAYQAMCNBUQ3PY5FO3— AWS Access Key ID in publichelm/corezoid/values.yamladmin_bearer_token_secret: ungoh3mohM3valu6Zu1ohdiighie1EemoophaequohMoov— admin auth token- Multiple RSA private keys including
ingress-tls.key,rabbitmq/tls-cert.key,default-server-secret.yaml,corezoid-demo.pem.j2(reused across 3 Ansible roles) - Postgres admin password
NE4wzHnodH9sbTeEfNaxDx23scM0ZaLS76xBiSIBhqT7EL4M3e - Multiple other API tokens and service credentials
Live-key validation of TLS key:
- Fingerprinted committed
ingress-tls.keypublic key: SHA-256b0ea83a9... - Fingerprinted live
*.corezoid.comcert public key: SHA-256021605b2... - No match → the leaked key is not currently deployed (rotated or never used). Good.
Semgrep SAST
Semgrep scan with
p/owasp-top-ten + p/security-audit + p/secrets across 5
service-named repos yielded 2 findings total:
account/charts/account-frontend/templates/configmap.yaml:64—$hostin nginx access_log format. False positive — using$hostin logs is normal, not a routing decision.gitcall-livekit-agent/Dockerfile:20— missingUSERdirective; container runs as root by default. Real low-severity hardening rec (noted in audit summary, not separately filed).
IaC review — Phase 7
Checkov scan on repos-src/helm (Helm umbrella
chart):
- 1387 passing checks, 377 failing, across 110 k8s resources
- Failures cluster into 20 distinct check IDs
- Filed as CRZ-010 (Medium, systemic)
Top 10 most-common failures:
- 75×
CKV_K8S_21— default namespace used - 19×
CKV_K8S_40— low-UID containers - 19×
CKV_K8S_38— service-account token mounted unnecessarily - 19×
CKV_K8S_43— images pulled by tag, not digest - 18×
CKV_K8S_37— capabilities assigned to containers - 18×
CKV_K8S_31— seccomp not set - 18×
CKV_K8S_20—allowPrivilegeEscalation: true - 18×
CKV_K8S_22— writable root filesystem - 18×
CKV_K8S_28—NET_RAWcapability allowed - 17×
CKV_K8S_29— no pod-level securityContext
Remediation plan in action-plan.md P2.1.
Edge infrastructure — Phase 8
See notes/phase8-edge.md.
Summary:
jira.corezoid.com— CRZ-006 Criticalcorezoid-ma.dev.corezoid.com:22— CRZ-007 Hightrack.pre.corezoid.com— CRZ-002 Highadmin-pre.corezoid.com— CRZ-001 Lowvpn.corezoid.com— CRZ-005 Infogitlab-mambu.corezoid.com,git.corezoid.com,confluence-ferma.corezoid.com— unresponsive / offline from testing location; recommend internal audit
Findings catalog
See findings/INDEX.md
for the master list with links to full writeups.
| ID | Severity | Title | Asset |
|---|---|---|---|
| CRZ-006 | 🔴 Critical | Jira Server 7.12.3 (2018 EOL) — multiple unauth RCE CVEs | jira.corezoid.com |
| CRZ-009 | 🔴 High (Critical-adjacent) | 41+ secrets in public GitHub repos | corezoid/helm, corezoid_ansible_roles |
| CRZ-002 | 🟠 High | Public Kubernetes API server (EKS pre-prod) | track.pre.corezoid.com |
| CRZ-007 | 🟠 High (conditional) | OpenSSH 8.7 public, vulnerable to regreSSHion | corezoid-ma.dev.corezoid.com:22 |
| CRZ-008 | 🟡 Medium | Auth cookie without SameSite; GET endpoints accept mw
alone |
admin.corezoid.com |
| CRZ-010 | 🟡 Medium | Systemic Kubernetes hardening gaps (377 checkov failures) | corezoid/helm charts |
| CRZ-011 | 🟡 Medium | Weak TLS (TLSv1.1, 3DES Sweet32, non-PFS ciphers) | vpn.corezoid.com |
| CRZ-012 | 🟡 Medium | Public API uses SHA-1 (non-HMAC) for request signing | api.corezoid.com + all /api/2/* |
| CRZ-015 | 🟡 Medium | Widget shim postMessage accepts messages via user-controlled appName (origin check bypass) | widget.simulator.company/shim.js |
| CRZ-013 | 🔵 Low-Med | Workflow CRUD destructive ops w/o confirmation/audit/MFA | admin.corezoid.com/api/2/json |
| CRZ-003 | 🔵 Low | Default nginx welcome on production ALB | widget.simulator.company |
| CRZ-001 | 🔵 Low | RFC1918 IPs in public DNS | admin-pre.corezoid.com |
| CRZ-004 | ⚪ Info | Prod docs as publicly-shareable Google Doc | doc.corezoid.com |
| CRZ-005 | ⚪ Info | OpenVPN-AS version disclosure | vpn.corezoid.com |
| CRZ-014 | ⚪ Info | Super-user grants cross-tenant workspace CRUD (authz granularity) | admin.corezoid.com/api/2/json |
Defenses confirmed working
Things that were tested and are correctly configured — mentioned so they aren't lost in remediation noise:
- CORS / SOP on admin API — cross-origin requests from malicious sites blocked by browser SOP; preflight returns 405
- IDOR defense on
/api/2/json— consistent error for valid-but-foreign and invalid IDs; no enumeration leak - Super-user != company-admin —
is_super_user: truedoes NOT bypass company-level authorization (least-privilege design) - HSTS with
includeSubDomainson all primary hosts - CSP defined on admin.corezoid.com with specific
allow-lists (has
'unsafe-inline' 'unsafe-eval'— real but lower-priority hardening) - x-frame-options: SAMEORIGIN,
x-content-type-options: nosniff,x-xss-protection: 1; mode=block - HTTPS redirect + TLS 1.3 on all primary hosts
- Jira ContactAdmin form disabled — mitigates the most dangerous CVE-2019-11581 anonymous vector
- Jira Ehcache RMI ports filtered — mitigates CVE-2020-36239
- Jira issue/project data anonymous-access-denied — anonymous users see 0 projects/issues
- OpenVPN-AS admin port 8888 closed — no public admin interface
- ACM wildcard TLS certs on primary hosts (rotation-friendly)
admin-oleg.dev.corezoid.com— all 1000 top ports filtered (not publicly reachable despite the DNS entry)- Stripe, reCAPTCHA keys in /system/conf are public-by-design — not credential leaks despite looking like them
- Session cookies have
HttpOnly; Securecorrectly set (preventing JS access, HTTPS-only transmission) superadmin.corezoid.comdoesn't exist (NXDOMAIN) — no super-admin surface accessible at all- Content-Security-Policy
frame-ancestors 'self'— prevents clickjacking permissions-policy: geolocation=(), camera=()— correctly restricts sensitive browser APIs- EKS private subnet ALBs — the
internal-*ELB pattern shows correct network segregation even if DNS leaks internal IPs - Checkov: 1387 passing checks — substantial baseline hardening exists; the 377 failures are gaps, not complete absence
Out-of-scope observations
Things noticed but NOT pursued (not in scope, or RoE limits):
admin.control.eventsredirects tosim.simulator.company— cross-brand redirect suggests historical migration; out of scopecontrol.eventsdomain — third-party, not part of this engagementwidget.sender.mobi— third-party, referenced in admin CSPbuilder.sender.mobi— same- Named customer subdomains (
gitlab-mambu,confluence-ferma,4ages.sandbox) — strongly recommend separate per-customer pentests if these are customer-dedicated instances; multi-tenancy of customer-named subdomains is not assessed here
Next steps
- Remediate P0 findings within 24 hours (CRZ-006, CRZ-009)
- Complete P1 within 7 days (CRZ-002, CRZ-007, CRZ-008)
- Re-test specific fixes — happy to run a focused re-scan after remediation to confirm
- Commission a deeper follow-up engagement with
internal source-code access (
git.corezoid.com) and fresh authenticated HAR captures for simulator.company — the current engagement was limited by what was visible externally + in public GitHub repos
Part 3 — Action plan
Format: Prioritized checklist with owner suggestion, effort estimate, success criteria. Owners are suggestions — adjust to your org structure.
🔴 P0 — Do now (within 24 hours)
P0.1 — Take Jira offline or migrate
- Finding: CRZ-006
- Owner: IT-ops + CTO decision
- Effort: 2–4h to make offline; 1–3 months to migrate to Cloud/DC 10.x
- Steps:
- [ ] Put
jira.corezoid.combehind VPN-only (restrict public ingress in ALB listener) - [ ] Announce read-only maintenance to users
- [ ] Begin migration evaluation: Jira Cloud vs Data Center 10.x
- [ ] Full Jira access-log review for suspicious activity over the last 7.5 years
- [ ] Assume compromise of any credential pasted into a ticket/comment historically; rotate
- [ ] Put
- Success criteria:
jira.corezoid.comnot reachable from public IP; migration plan signed off
P0.2 — Rotate all leaked secrets from public repos
- Finding: CRZ-009
- Owner: DevOps / SRE
- Effort: 4–8 hours for rotation; 2 days for CloudTrail audit
- Steps:
- [ ] Deactivate AWS IAM key
AKIAYQAMCNBUQ3PY5FO3 - [ ] CloudTrail search for that Access Key ID for last 400 days
- [ ] Rotate
admin_bearer_token_secret(ungoh3mohM3valu6Zu1ohdiighie1EemoophaequohMoov) - [ ] Rotate all postgres admin passwords
(
NE4wzHnodH9sbTeEfNaxDx23scM0ZaLS76xBiSIBhqT7EL4M3eetc.) - [ ] Revoke and re-issue all TLS certs whose private keys appeared in git history; CT-log check for existing certs tied to compromised pubkeys
- [ ] Rotate all "api key"-flagged tokens from the inventory in CRZ-009
- [ ] Rotate ArgoCD tokens in
terraform/modules/eks/variables.tf(confirm if real or example first) - [ ] Audit Ansible box-credentials and postgres reset scripts — rotate
- [ ] Deactivate AWS IAM key
- Success criteria: All 41+ listed secrets replaced; CloudTrail shows no unauthorized use
🟠 P1 — Do this week (within 7 days)
P1.1 — Lock down EKS control plane
- Finding: CRZ-002
- Owner: DevOps / Platform
- Effort: 2–4 hours
- Steps:
- [ ] Identify why
track.pre.corezoid.comDNS points at an EKS API (likely a Route53 misroute) - [ ] Change EKS cluster endpoint access to private
or public+allowlist (via
aws eks update-cluster-config) - [ ] If public+allowlist needed: limit to corporate VPN egress IPs + CI/CD build runners
- [ ] Add CloudWatch alarm on
/healthz,/readyz,/livezrequest volume from non-corporate IPs - [ ] Audit all other
*.corezoid.comDNS entries for similar misroutes to cluster endpoints
- [ ] Identify why
- Success criteria:
curl https://track.pre.corezoid.com/from any public network → connection refused / DNS fails
P1.2 — Remove public SSH on dev hosts
- Finding: CRZ-007
- Owner: SRE
- Effort: 4–8 hours
- Steps:
- [ ] Block port 22 from internet on
corezoid-ma.dev.corezoid.com(AWS security group update) - [ ] Audit all
*.dev.corezoid.comand*.pre.corezoid.comhosts for similar public SSH exposure - [ ] Migrate developer access to:
- AWS SSM Session Manager (no SSH daemon needed), or
- VPN-only SSH, or
- Teleport / Tailscale SSH
- [ ] Upgrade OpenSSH on the host to ≥ 9.8p1 regardless
- [ ] Audit
/etc/ssh/sshd_configforPasswordAuthentication no,PermitRootLogin no - [ ] Rotate all SSH keys in
~/.ssh/authorized_keyson the host
- [ ] Block port 22 from internet on
- Success criteria:
nmap -p 22 *.dev.corezoid.comreturns filtered/closed from public
P1.3 — Fix auth cookie SameSite
- Finding: CRZ-008
- Owner: Backend (admin.corezoid.com team)
- Effort: 1–2 days (including QA)
- Steps:
- [ ] Add explicit
SameSite=Stricttomwcookie Set-Cookie header - [ ] Require both
mwand__Host_mwcookies on ALL authenticated endpoints (currently GET endpoints acceptmwalone) - [ ] Rename
__Host_mw→__Host-mw(hyphen instead of underscore) so browsers enforce host-prefix rules — OR drop the fake-looking name - [ ] Change
GET /logouttoPOST /logoutwith CSRF token - [ ] Consider reducing cookie
Domain=.corezoid.com→Domain=admin.corezoid.com(blast-radius reduction) - [ ] QA cross-origin behavior from a test origin before deploying
- [ ] Add explicit
- Success criteria: Unit test:
GET /auth/mewith onlymwcookie returns 401, not 200
🟡 P2 — Do this sprint (within 2 weeks)
P2.1 — Apply Kubernetes hardening defaults
- Finding: CRZ-010
- Owner: Platform team
- Effort: 1–2 sprints, phased
- Phase 1 (this sprint): umbrella chart
values.yamldefaults- [ ] Set
podSecurityContext+securityContextdefaults as shown in CRZ-010 - [ ] Set
automountServiceAccountToken: falsedefault; override per-chart where needed - [ ] Set CPU/memory requests + limits defaults
- [ ] Verify in staging; expect some pods to crashloop (root-required workloads); add per-chart overrides
- [ ] Set
- Phase 2: namespace migration 5. [ ] Create
namespaces:
account,apigw,workers,simulator,db,messaging,observability6. [ ] Migrate resources offdefaultnamespace - Phase 3: network policies 7. [ ] Install Cilium or Calico (if not already) 8. [ ] Default-deny NetworkPolicy per namespace 9. [ ] Allow-list specific service-to-service traffic
- Phase 4: supply chain 10. [ ] Pin all images by
digest (not tag) 11. [ ] Extend cosign verification (already in
account) cluster-wide via Kyverno / Gatekeeper 12. [ ] Add Renovate / digestabot for digest updates - Success criteria: Checkov re-run shows <50 failures (from 377); CI gate fails PRs that regress checkov score
P2.2 — Remove dead DNS/ALB entries
- Findings: CRZ-003, CRZ-001
- Owner: SRE
- Effort: 2–4 hours
- Steps:
- [ ] Remove
widget.simulator.companyDNS record (or fix the nginx routing) - [ ] Remove
admin-pre.corezoid.comfrom public Route53, move to Private Hosted Zone - [ ] Audit every other public DNS record — cross-check against current service inventory
- [ ] Remove entries for:
admin-oleg.dev.corezoid.com(if dev no longer active),corezoid-6102-*(old version deployments),corezoid69-*(even older),4ages.sandbox.corezoid.com(customer sandbox, verify), etc.
- [ ] Remove
P2.3 — Audit doc.corezoid.com Google Doc
- Finding: CRZ-004
- Owner: Docs team / CTO
- Effort: 4 hours for audit; 2 weeks for migration
- Steps:
- [ ] Check share setting on the Google Doc
(
1-31BBNhy2DUIfu-EljVn3MJr3GSOVqJ3PIwjGPUi3So) - [ ] Review revision history for any sensitive content ever pasted
- [ ] If share is "anyone with link can comment/edit" — lock down immediately
- [ ] Plan migration to a controlled CMS (Docusaurus / ReadMe.io / Mkdocs-material)
- [ ] Check share setting on the Google Doc
(
- Success criteria: docs are version-controlled and access is managed by a real authorization system
🔵 P3 — Do this quarter (within 90 days)
P3.1 — Org-wide secret management
- Owner: Security team
- Effort: 1 quarter
- Steps:
- [ ] Install pre-commit hooks (
gitleaks,detect-secrets) org-wide - [ ] Enable GitHub secret scanning + push protection on all Corezoid repos
- [ ] Migrate Helm values away from containing secrets — use Sealed Secrets, External Secrets Operator, or Vault
- [ ] Enforce IAM key rotation policy (90 days max) via AWS Config + Lambda
- [ ] Quarterly trufflehog+gitleaks sweep of all repos (including archived) — dashboard the results
- [ ] Publish a "Secrets Handbook" for developers
- [ ] Install pre-commit hooks (
P3.2 — Close Jira migration + secrets cleanup loop
P3.3 — Expand testing coverage
Tracking
| Priority | Count | Findings |
|---|---|---|
| 🔴 P0 | 2 | CRZ-006 (Jira EOL), CRZ-009 (public-repo secrets) |
| 🟠 P1 | 5 | CRZ-002 (k8s public), CRZ-007 (OpenSSH regreSSHion), CRZ-008 (SameSite), CRZ-011 (VPN TLS), CRZ-015 (postMessage origin) |
| 🟡 P2 | 4 | CRZ-010 (k8s hardening), CRZ-013 (destructive-op audit), CRZ-003 (widget nginx), CRZ-001 (admin-pre DNS) |
| 🔵 P3 | 4 | CRZ-012 (SHA-1 signatures → HMAC-SHA256 migration), CRZ-004 (Google Doc), CRZ-014 (super-user scope), org-wide secret mgmt |
| ⚪ Info | 1 | CRZ-005 (OpenVPN-AS version — monitor) |
Total findings: 15 (1 Critical, 3 High, 5 Medium, 3 Low/Low-Med, 3 Info). Engagement complete; no more findings pending.
End of full report. Individual finding detail files: see
findings/CRZ-*.md