Penetration test report
Security posture assessment with application and API penetration test
Example Ltd
Example Ltd is fictional: a 60-person software company with a customer portal, a Microsoft 365 tenant and a small AWS footprint. This sample is illustrative and contains no client data.
1Section
Executive summary
The question
Where is the business exposed, and is the customer portal secure?
Overall postureAt riskGood, with two items in progress
Example Ltd asked a simple question: where is the business exposed, and is the customer portal secure? Over two weeks, our AI agents examined everything Example Ltd shows the internet, its Microsoft 365 tenant and its customer portal, and our testers confirmed twelve findings.
Four were high risk. An old admin portal was still online with outdated software. Three administrator accounts were not protected by multi-factor authentication. In the customer portal, two weaknesses combined to let one customer download another customer's exports, and sessions stayed active after a password change.
All four were fixed and verified on retest by 30 September. Two lower-risk items are in progress, and one is an accepted risk.
What's working
- Production and staging are well separated.
- The main website and email service are patched promptly.
- Clear ownership: urgent findings were fixed within two days of being raised.
Priorities now
- Finish the invitation fix on the bulk-invite path (ZP-06).
- Move email protection from quarantine to reject (ZP-10).
- Keep an inventory of internet-facing systems and review it quarterly.
Recommended next step
The customer portal ships weekly. Regular retesting would re-check these fixes and test new releases as they ship.
2Section
Posture at a glance
How exposed each area was when testing started, and where it stands after the retest.
| Area | Before | After retest | What changed |
|---|---|---|---|
| Internet-facing systems | At risk | Good | The forgotten admin portal is offline. Older encryption on one site is an accepted risk. |
| Customer portal and API | At risk | Needs attention | All high-severity issues fixed. The bulk-invite path still accepts a role from the browser. |
| Microsoft 365 | At risk | Good | Multi-factor authentication now covers every administrator. |
| Cloud storage | Needs attention | Good | Public listing disabled and internal files moved. |
| Code and secrets | Needs attention | Good | The leaked key is revoked and secret scanning is on. |
| Email and domain | Needs attention | Needs attention | Spoofed email is now quarantined; blocking is planned. |
3Section
Findings at a glance
- 0Critical
- 4High
- 4Medium
- 3Low
- 1Info
| ID | Finding | Area | Severity | After retest |
|---|---|---|---|---|
| ZP-01 | Forgotten admin portal online with outdated software | Internet-facing systems | High | Fixed |
| ZP-02 | Three administrator accounts without multi-factor authentication | Microsoft 365 | High | Fixed |
| ZP-03 | Cross-workspace access to exports | Customer portal | High | Fixed |
| ZP-04 | Sessions survive a password change | Customer portal | High | Fixed |
| ZP-05 | Sequential export identifiers | Customer portal | Medium | Fixed |
| ZP-06 | Invitation role accepted from the browser | Customer portal | Medium | Partially fixed |
| ZP-07 | Storage container lists file names publicly | Cloud storage | Medium | Fixed |
| ZP-08 | Email-service key in a public repository still valid | Code and secrets | Medium | Fixed |
| ZP-09 | Detailed error messages | Customer portal | Low | Open |
| ZP-10 | Email domain not fully protected against spoofing | Email and domain | Low | Partially fixed |
| ZP-11 | Password reset links last seven days | Customer portal | Low | Fixed |
| ZP-12 | Older encryption protocols accepted | Internet-facing systems | Info | Accepted risk |
4Section
Scope and approach
In scope
- example.com, its subdomains and the services they expose
- The customer portal (app.example.com) and its API (api.example.com): staging environment, three roles and two test workspaces
- The Microsoft 365 tenant, as a read-only configuration review
- Public code repositories and sources linked to example.com
- Storage buckets in the AWS account that serve the website
Out of scope
- The internal office network
- Staff phishing and physical security
- Denial-of-service testing
- The third-party payment provider
Rules of engagement
- Written authorisation from Example Ltd for every system in scope
- Testing on weekdays, 08:00 to 18:00 UK time
- Portal traffic limited to 4 requests per second
- Anything that could change or delete data held for approval
- A named stop contact on both sides
How we tested
AI agents mapped and tested the scope in parallel, with every action checked against the agreed scope before it ran. Experienced testers steered the work, confirmed every finding and rated its severity for Example Ltd's business. References: the OWASP Web Security Testing Guide and ASVS for the portal, and the CIS Microsoft 365 Foundations Benchmark for the tenant.
5Section
Attack path
Individual findings matter less than what they lead to. This path shows how two findings combined.
AP-01
A Viewer in workspace A reads workspace B's documents
- StartViewer role, workspace AAgreed test identity
- ZP-05, mediumExport IDs are sequentialValid IDs for other workspaces are predictable
- ZP-03, highNo ownership check on exportThe API trusts the ID it is given
- ObjectiveWorkspace B documentsMetadata and signed download links
Two individually moderate weaknesses combine into one high-impact path. Fixing ZP-03 closes it; fixing ZP-05 alone doesn't.
6Section
Findings in detail
ZP-01
Forgotten admin portal online with outdated software
What we found
An administration portal replaced in 2024 is still reachable from the internet. It runs a version of its software with a published high-severity vulnerability.
Why it matters
The old portal still holds customer contact records. An outsider who used the vulnerability could reach them, and nobody was watching the system.
Root cause
Decommissioning removed the portal from use but not from the internet, and there is no owned inventory of internet-facing systems.
How to fix it
Take the portal offline and remove its DNS record. Keep an inventory of internet-facing systems and review it every quarter.
ZP-02
Three administrator accounts without multi-factor authentication
What we found
Three of five global administrator accounts were excluded from the policy that requires multi-factor authentication.
Why it matters
A stolen or guessed password for any of these accounts would give full control of email, files and every user account.
Root cause
The accounts were excluded during a 2025 migration and never added back.
How to fix it
Require phishing-resistant multi-factor authentication for every administrator, keep two monitored emergency accounts, and review policy exclusions monthly.
ZP-03
Cross-workspace access to exports
What we found
Signed in as a Viewer in one customer's workspace, we could download exports belonging to another customer.
Why it matters
Any customer could read other customers' documents, which is likely to be a reportable personal data breach.
Root cause
Workspace ownership is enforced in the interface but not in the export service.
How to fix it
Scope every export lookup to the caller's workspace in the service layer, and add a regression test that fails if it ever isn't.
Evidence: request and response
GET /api/v2/exports/10482 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOi... # viewer, workspace A
HTTP/1.1 200 OK
content-type: application/json
{ "id": 10482, "workspace": "ws_b", "name": "Q3 contracts.zip",
"download_url": "https://files.example.com/...[redacted]" }Other findings
In a full engagement report, each of these has the same write-up as above.
| ID | Finding | Severity | Fix |
|---|---|---|---|
| ZP-04 | Sessions survive a password changeChanging a password did not sign out the account's other sessions. | High | End every other session when a password changes, and offer users a “sign out everywhere” option. |
| ZP-05 | Sequential export identifiersExport identifiers are sequential, so valid identifiers for other workspaces are easy to predict. | Medium | Use random, unguessable identifiers for exports and other shared objects. |
| ZP-06 | Invitation role accepted from the browserWhen inviting a colleague, the role sent from the browser was trusted, so an Editor could invite an Admin. | Medium | Check on the server that the inviter can grant the requested role, on every invitation path. |
| ZP-07 | Storage container lists file names publiclyA storage bucket for website images let anyone list its contents, including two internal price lists. | Medium | Block public listing, move internal files to private storage, and serve images through the website. |
| ZP-08 | Email-service key in a public repository still validA key for the email-sending service was committed to a public repository in 2023 and still worked. | Medium | Revoke and replace the key, and turn on secret scanning for every repository. |
| ZP-09 | Detailed error messagesSome errors return internal details, including software versions. | Low | Return generic errors to users and log the detail internally. |
| ZP-10 | Email domain not fully protected against spoofingThe domain's email policy only monitors spoofed messages rather than blocking them. | Low | Move the policy to quarantine, then reject, once legitimate senders are confirmed. |
| ZP-11 | Password reset links last seven daysReset links remain valid for seven days and can be used more than once. | Low | Expire reset links after an hour and after first use. |
| ZP-12 | Older encryption protocols acceptedThe marketing site still accepts TLS 1.0 and 1.1 alongside modern versions. | Info | Disable TLS 1.0 and 1.1 at the hosting provider. |
7Section
Retest record
Every finding re-tested against the deployed fix on 30 September 2026, with the original evidence as the baseline.
| ID | Finding | Result | Note |
|---|---|---|---|
| ZP-01 | Forgotten admin portal online with outdated software | Fixed | Portal offline; hostname no longer resolves. |
| ZP-02 | Three administrator accounts without multi-factor authentication | Fixed | All administrators now covered; exclusions reviewed. |
| ZP-03 | Cross-workspace access to exports | Fixed | Cross-workspace export IDs now return 404. |
| ZP-04 | Sessions survive a password change | Fixed | Original scenario no longer reproduces. |
| ZP-05 | Sequential export identifiers | Fixed | Original scenario no longer reproduces. |
| ZP-06 | Invitation role accepted from the browser | Partially fixed | Single invites fixed; the bulk-invite path still accepts a role. |
| ZP-07 | Storage container lists file names publicly | Fixed | Original scenario no longer reproduces. |
| ZP-08 | Email-service key in a public repository still valid | Fixed | Original scenario no longer reproduces. |
| ZP-09 | Detailed error messages | Open | Scheduled by Example Ltd for the October release. |
| ZP-10 | Email domain not fully protected against spoofing | Partially fixed | Moved to quarantine; reject planned. |
| ZP-11 | Password reset links last seven days | Fixed | Original scenario no longer reproduces. |
| ZP-12 | Older encryption protocols accepted | Accepted risk | Accepted until the site moves host in December. |
AAppendix
Coverage and limitations
| Ref | Area | Status |
|---|---|---|
| EXT | Internet-facing discovery and testing | Tested |
| M365 | Microsoft 365 configurationRead-only review | Tested |
| WSTG-ATHN | Portal authentication | Tested |
| WSTG-ATHZ | Portal authorisation | Tested |
| WSTG-SESS | Portal session management | Tested |
| WSTG-INPV | Portal input validation | Tested |
| WSTG-BUSL | Portal business logic | Tested |
| WSTG-APIT | API testing | Tested |
| AWS | Cloud storage serving the websiteStorage only; no full cloud test | Partial |
| — | Internal network and phishing | Out of scope |
| — | Denial of serviceExcluded in rules of engagement | Out of scope |
This report describes what was tested during the testing window, against the agreed scope. It does not certify that no other vulnerabilities exist, and a clean result in an area is evidence of what was examined, not a guarantee.
Findings separate what was observed, what was suspected but not confirmed, and what was not tested and why.
BAppendix
Letter of attestation
To whom it may concern,
Zarco carried out an authorised security posture assessment with application and API penetration test for Example Ltd, under written rules of engagement agreed with Example Ltd.
- Scope
- example.com, app.example.com, api.example.com and the Microsoft 365 tenant
- Testing window
- 1 to 12 September 2026
- Method
- Agent-assisted testing with tester validation, against OWASP WSTG and ASVS and the CIS Microsoft 365 benchmark
- Results
- 0 critical, 4 high, 4 medium, 3 low, 1 info
- Retest
- All four high-severity findings fixed and verified on 30 September 2026
This is a point-in-time assessment of the agreed scope. It does not certify that the systems are free of vulnerabilities.
Lead tester, Zarco
1 October 2026