External Penetration Test Report
XYZ-Company
1. Executive Summary
XYZ-Company engaged REDWULF Security Consulting to perform an external penetration test of their public-facing infrastructure. The assessment was conducted over 4 days from a black-box perspective — with no credentials, documentation, or privileged access provided.
Key Findings
The assessment identified 7 vulnerabilities across the external attack surface. Of particular concern is a critical-severity finding involving exposed cluster bootstrap infrastructure that disclosed credentials granting root-level access to all nodes in the production Kubernetes cluster.
| Severity | Count | Finding IDs |
|---|---|---|
| CRITICAL | 1 | RPT-05 |
| HIGH | 3 | RPT-01, RPT-06, RPT-07 |
| MEDIUM | 1 | RPT-03 |
| LOW / INFO | 2 | RPT-02, RPT-04 |
2. Scope & Methodology
Target Scope
xyz-company.ioand all discovered subdomains- All TCP/UDP ports on the primary public IP addresses
- Web applications hosted on the identified infrastructure
- APIs and supporting services accessible from the internet
Methodology
Testing followed the Penetration Testing Execution Standard (PTES) technical guidelines, with severity rated using CVSS v3.1.
- Reconnaissance — DNS enumeration, port scanning, service fingerprinting, technology stack identification
- Vulnerability Identification — Automated scanning combined with targeted manual testing of identified services
- Exploitation & Validation — Safe exploitation to confirm impact without causing disruption, data loss, or downtime
- Post-Exploitation Analysis — Lateral movement assessment and impact analysis where applicable
- Reporting — Findings documented with evidence, risk ratings, attack paths, and remediation guidance
3. Detailed Findings
Container Platform Machine Config Server Exposed — Full Cluster Bootstrap Secrets Disclosed
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N
Summary
The Container Platform Machine Config Server (MCS) was found exposed on a non-standard port without any authentication. This endpoint serves complete ignition bootstrap configurations for both control-plane and worker nodes, disclosing SSH keys granting root access to all cluster nodes, the Kubernetes CA certificate, the internal API server address, and full cluster infrastructure configuration.
Steps to Reproduce
- Reconnaissance revealed an exposed HAProxy statistics endpoint on port 9000, listing all backend services.
- The backend list included a service named
platform_machine_config_server_bemapped to port 22623. - Requesting the master node ignition config returned a 914 KB JSON file — no authentication required.
Technical Details
The ignition configuration contained SSH key material granting root-level access to all control-plane and worker nodes (via the core user with passwordless sudo), the Kubernetes CA certificate (root of trust for the entire cluster), the internal API server address and service network configuration, container runtime configuration including registry credentials, and static pod manifests for control-plane components. The same SSH key was present in both master and worker configurations, meaning compromise of any single node key compromises the entire cluster.
Proof of Concept
$ curl -sk https://123.456.789.10:22623/config/master | wc -c 914318 $ curl -sk https://123.456.789.10:22623/config/master | grep -o 'ssh-[^"]*' ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFAKEKEYEXAMPLE000000000000 services $ curl -sk https://123.456.789.10:22623/config/master | grep -o 'api-int\.[^'\\']*' api-int.c1.xyz-company.io $ curl -sk https://123.456.789.10:22623/config/master | grep 'certificate-authority-data' certificate-authority-data: LS0tLS1CRUdJTi...[REDACTED]...
Impact
Complete cluster compromise. With the extracted SSH key, an attacker gains root shell access to every node in the cluster, full control of all containers and workloads, access to all persistent volumes and their data (databases, file storage), Kubernetes cluster admin access by extracting service account tokens from node filesystems, and the ability to deploy malicious workloads.
Remediation
- Immediately remove the MCS backend from the public-facing load balancer configuration
- Rotate the exposed SSH key on all nodes
- Rotate the Kubernetes CA certificate and all node certificates
- Firewall the MCS port to only allow access from the internal cluster network
- Audit all node authorized_keys files for unauthorized additions
Cluster Web Console & OAuth Server Publicly Exposed with Built-in Admin Identity Provider
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Summary
The cluster web console and OAuth authentication server are publicly accessible. The login page reveals two identity providers, including the built-in platform administrator account. The login form is fully functional and accepts credential attempts, enabling brute force attacks against the most privileged cluster account.
Steps to Reproduce
- The web console was discovered through backend enumeration from the HAProxy statistics exposure.
- The console redirected to the OAuth server, which displayed a login page with the built-in admin identity provider.
- The login form accepted credential submissions and visibly distinguished between valid and invalid credentials via distinct error redirects.
- The GitHub OAuth flow was also exposed, revealing the organization-scoped OAuth application client ID.
Technical Details
The OAuth server login endpoint accepts POST requests with username/password fields and a CSRF token. Failed attempts redirect with reason=authentication_error, confirming credential validity checks. No rate limiting was observed in server responses — each request was processed without delay or lockout. The login form uses PatternFly v6 CSS framework (OKD/OpenShift standard).
Proof of Concept
$ curl -sk -o /dev/null -w "%{http_code}" \
https://console-openshift-console.apps.c1.xyz-company.io/
200
$ curl -sk "https://oauth-openshift.apps.c1.xyz-company.io/oauth/authorize\
?client_id=console&idp=kube:admin&redirect_uri=..."
→ 302 → /login (login form served)
$ curl -sk -X POST "https://oauth-openshift.apps.c1.xyz-company.io/login" \
-d "username=kubeadmin&password=test123&csrf=..."
→ 302 → /login?reason=authentication_error
(credentials rejected — endpoint functional, confirms valid/invalid distinction)
Impact
Brute force attack surface against the cluster's most privileged account; full cluster admin compromise if credentials are guessed; GitHub OAuth client ID exposure enables phishing attacks targeting the authorized organization; combined with Finding RPT-05 (CA certificates + SSH keys) and RPT-06 (direct K8s API access), this provides the authentication endpoint needed to complete cluster compromise.
Remediation
- Restrict the web console and OAuth endpoints to internal/VPN IPs only
- Implement rate limiting on the OAuth /login endpoint
- Disable or rotate the built-in admin account (use only SSO/OIDC for cluster admin)
- Enable audit logging for all authentication attempts
- Consider an OIDC provider with MFA instead of static credentials
Infrastructure Monitoring Interface Exposed Without Authentication
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Summary
The HAProxy statistics interface was accessible on port 9000 without any authentication. This endpoint reveals the complete backend infrastructure topology, including all internal service hostnames, ports, health status, traffic metrics, and session rates — providing an attacker with a detailed network map for targeted exploitation.
Steps to Reproduce
- Port scanning of the public IP range revealed an open HTTP service on port 9000.
- Requesting the root path returned the full HAProxy Statistics Report in HTML format.
- The report listed every backend server group with server names, addresses, ports, and current operational status.
Technical Details
The statistics page disclosed backend names such as platform_machine_config_server_be (port 22623), platform_k8s_api_be (port 6443), platform_https_ingress_traffic_be, platform_oauth_be, and webmail_be. Each entry included the backend server address, current session count, bytes in/out, health check status, and error rates.
Proof of Concept
$ curl -s http://123.456.789.10:9000/ | grep -o 'platform_[a-z_]*_be' platform_machine_config_server_be platform_k8s_api_be platform_https_ingress_traffic_be platform_oauth_be $ curl -s http://123.456.789.10:9000/ | grep -E '^[a-z]+.*(UP|DOWN)' webmail_be 123.456.789.10 UP 0 128 45678 98765 platform_k8s_api_be 123.456.789.10 UP 12 2048 1234567 2345678 [Full backend table with session rates, bytes in/out, and health status]
Impact
Complete infrastructure topology disclosure. An attacker gains a comprehensive map of all internal services, their addresses, and their roles — eliminating the reconnaissance phase entirely. Specific backend names directly revealed the technology stack and enabled targeted attacks against the cluster infrastructure.
Remediation
- Remove the HAProxy stats endpoint from the public-facing frontend configuration
- Bind the stats socket to localhost only, or require HTTP Basic Authentication
- If remote monitoring access is needed, expose it via VPN or SSH tunnel, not the public internet
Kubernetes API Server Directly Exposed to the Internet
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Summary
The Kubernetes API server is directly accessible from the public internet on port 6443. While anonymous access to API resources is properly restricted (HTTP 403), the API server returns version information, health status, and OAuth discovery metadata without authentication, expanding the attack surface significantly.
Steps to Reproduce
- Accessed port 6443 on both public IPs — both responded with the Kubernetes API server TLS handshake.
- The
/versionendpoint returned the exact Kubernetes version, Go compiler version, and build date. - The
/healthz,/readyz, and/livezendpoints all responded without auth. - The
/.well-known/oauth-authorization-serverendpoint exposed OAuth grant types and endpoints. - Resource endpoints properly returned 403 for anonymous access.
Technical Details
The API server disclosed Kubernetes v1.34.7 compiled with Go 1.24.13 (Red Hat build). The OAuth discovery endpoint returned issuer URL, authorization endpoint, token endpoint, and supported scopes. Combined with extracted CA certificates (Finding RPT-05) and exposed OAuth login (Finding RPT-07), all components for cluster compromise are in place — only valid credentials are missing.
Proof of Concept
$ curl -sk https://123.456.789.10:6443/version
{"major":"1","minor":"34","gitVersion":"v1.34.7",
"gitCommit":"ed28eb163cd976fbd2a8254f549e5ae8cb547977",
"buildDate":"2026-04-30T21:19:28Z","goVersion":"go1.24.13",
"compiler":"gc","platform":"linux/amd64"}
$ curl -sk https://123.456.789.10:6443/healthz
ok
$ curl -sk https://123.456.789.10:6443/.well-known/oauth-authorization-server
{"issuer":"https://oauth-openshift.apps.c1.xyz-company.io",
"authorization_endpoint":"https://oauth-openshift...",
"token_endpoint":"https://oauth-openshift.../oauth/token",
"scopes_supported":["user:check-access","user:full","user:info","user:list-projects"]}
$ curl -sk https://123.456.789.11:6443/version
{"major":"1","minor":"34",...}
[Confirmed accessible on both public IPs]
Impact
Direct attack surface for Kubernetes API CVEs without requiring VPN or bastion access. Version disclosure enables targeted vulnerability research. Combined with the extracted CA certificate and exposed OAuth endpoints, this creates a complete attack chain for cluster compromise.
Remediation
- Firewall port 6443 to allow access only from the internal cluster network and trusted management IPs
- Verify the load balancer frontend is bound to internal interfaces only
- Set up VPN for administrative Kubernetes API access
- Enable API server audit logging
Session Token Exposed in URL Query String
AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N
Summary
The authenticated session token is passed as a URL query parameter during a redirect from the main application to the builder subdomain. This exposes the session token via the Referer header to third-party services, stores it in browser history, and leaves it in server and proxy logs.
Steps to Reproduce
- Authenticated to the main application as a regular user.
- Navigated to the campaign creation page, which triggered a redirect to the builder subdomain.
- The HTTP 302 redirect Location header contained the full session token as a
session_idquery parameter. - The session_id value was identical to the existing session cookie.
- The builder page loaded resources from 4 external domains (analytics, CDN, fonts), each receiving the full URL with the session token via the Referer header.
Technical Details
The redirect URL pattern was https://builder.xyz-company.io/?type=popup&session_id=<token>&lang=en&referrer=xyz. The session_id parameter value matched the xyz_sessionid cookie exactly. The builder page loads resources from Microsoft Clarity (analytics), Google Fonts, unpkg.com (CDN), and cdnjs.cloudflare.com — each receiving the session token in the Referer header.
Proof of Concept
$ curl -sI "https://app.xyz-company.io/on-site/create/popup/" \ -H 'Cookie: xyz_sessionid=sm38ntmftuj2q6adf3f5lv4kd2tpb5o9' HTTP/2 302 Location: https://builder.xyz-company.io/?type=popup\ &session_id=sm38ntmftuj2q6adf3f5lv4kd2tpb5o9&lang=en&referrer=xyz # session_id value == xyz_sessionid cookie value (identical) # Builder page loads → Referer sent to: fonts.googleapis.com, # cdnjs.cloudflare.com, unpkg.com, clarity.ms
Impact
Session tokens are leaked through multiple channels: the Referer header to at least 4 external domains (analytics, CDNs), browser history in plaintext, server access logs on the builder subdomain, and any intermediate proxy or gateway logs. An attacker obtaining the token can impersonate the victim and access their account.
Remediation
- Pass the session token only via the existing secure, HttpOnly cookie — do not duplicate it in URL parameters
- Have the builder subdomain read the session from the cookie, not the URL
- Alternatively, use a short-lived, single-use token (not the actual session ID) that expires after first use
Virtualization Management Interface Exposed
Summary
The Proxmox Virtual Environment management interface is exposed on port 8006 without IP restriction. While the interface requires authentication, it discloses the authentication realm through API responses and increases the attack surface for credential attacks and CVE exploitation.
Steps to Reproduce
- Port scanning revealed an HTTPS service on port 8006 running Proxmox VE.
- The Proxmox VE API returned realm information without authentication.
- The login page was fully accessible and accepted credential submissions.
Technical Details
The Proxmox VE API at /api2/json/access/domains disclosed configured authentication realms. The management interface version information enables targeted CVE research against known Proxmox vulnerabilities.
Proof of Concept
$ curl -sk https://123.456.789.10:8006/api2/json/access/domains
{"data":[{"realm":"pam","comment":"Linux PAM standard authentication"},
{"realm":"pve","comment":"Proxmox VE authentication server"}]}
$ curl -sk -o /dev/null -w "%{http_code}" https://123.456.789.10:8006/
200
$ curl -sk https://123.456.789.10:8006/ | grep -o 'Proxmox.*<'
Proxmox Virtual Environment
Impact
Increased attack surface for infrastructure compromise. Proxmox VE management provides full control over all virtual machines, including the Kubernetes cluster nodes. While authentication is required, the exposed interface enables credential brute forcing and CVE exploitation.
Remediation
- Restrict access to the management interface via VPN or IP allowlisting
- Implement rate limiting and fail2ban for Proxmox login attempts
- Consider moving management interfaces to a dedicated management network
Exposed Webmail & Groupware Interface
Summary
A webmail interface and groupware installation are exposed without IP restriction. While the login page itself does not leak data, the exposure increases the attack surface for credential brute forcing, phishing, and CVE exploitation.
Steps to Reproduce
- Discovered the webmail hostname via the HAProxy stats enumeration.
- Confirmed the webmail and groupware login pages were accessible without restriction.
- API status endpoints were reachable (redirected to login for unauthenticated requests).
Technical Details
The webmail installation was confirmed through HTML source analysis. The groupware interface was accessible at a predictable path. Internal API endpoints for container status were reachable (returning HTTP 200), though they redirected to the login page for unauthenticated requests.
Proof of Concept
$ curl -s https://mail.xyz-company.io/ | grep -o 'mailcow'
mailcow (multiple matches — confirmed installation)
$ curl -s -o /dev/null -w "%{http_code}" https://mail.xyz-company.io/SOGo/
200
$ curl -s -o /dev/null -w "%{http_code}" \
https://mail.xyz-company.io/api/v1/get/status/containers
200
Impact
Increases attack surface for email account compromise, credential brute forcing, CVE exploitation against the webmail and groupware software, and phishing (a convincingly branded login page on the legitimate domain).
Remediation
- Restrict access to the webmail interface via VPN or IP allowlisting
- Implement rate limiting for login attempts
- Deploy fail2ban for repeated authentication failures
4. Risk Matrix
CVSS v3.1 qualitative mapping used throughout this report:
| Rating | CVSS Score | Definition |
|---|---|---|
| CRITICAL | 9.0 – 10.0 | Immediate compromise of critical systems; full data exfiltration or system takeover possible without user interaction |
| HIGH | 7.0 – 8.9 | Significant impact to confidentiality, integrity, or availability; may enable lateral movement or privilege escalation |
| MEDIUM | 4.0 – 6.9 | Limited impact; requires user interaction, specific conditions, or combined with other weaknesses for exploitation |
| LOW | 0.1 – 3.9 | Minimal direct impact; information disclosure that aids reconnaissance; defense-in-depth concerns |
5. Conclusion & Recommended Next Steps
The penetration test identified 7 findings across the external attack surface, including one critical-severity infrastructure exposure that requires immediate attention.
Immediate Priorities (within 48 hours)
- Remove the cluster bootstrap configuration endpoint from public access (RPT-05) — this single change eliminates the most severe finding
- Rotate all exposed credentials: SSH keys, Kubernetes CA certificates, and node certificates (RPT-05)
- Restrict the cluster web console and OAuth endpoints to VPN-accessible IPs only (RPT-07)
Short-Term (within 2 weeks)
- Firewall the Kubernetes API server (RPT-06) and HAProxy statistics interface (RPT-01)
- Fix the session token exposure in URL query strings (RPT-03)
- Restrict webmail and virtualization management interfaces (RPT-02, RPT-04)
Ongoing
- Implement a regular external perimeter scanning schedule
- Conduct an internal network penetration test to assess lateral movement risks
- Schedule a retest after remediation to verify closure of all findings
Want a report like this for your application?