The previous lesson ended with a question neither the scanner in 05-01 nor the detection in 05-02 answers: would it really hold up? A scanner checks versions and a detection observes what happens, but neither tries to chain three small weaknesses together — a missing header, a rate limit that does not exist and a predictable identifier — into a real compromise. That is what an attacker does, and that is what a penetration test simulates. This lesson teaches you to commission one, scope it, understand it and get value from it, with a defensive focus: you will see what was found in Nimbus's environment and, above all, how each thing was fixed.
⚠️ Legal warning — this is the most delicate lesson in the course
Running intrusion techniques against someone else's system without written authorisation is a crime, not a prank. In Spain:
- Art. 197 bis of the Spanish Criminal Code: accessing, or enabling access to, all or part of an information system by circumventing its security measures, or intercepting non-public transmissions, is punishable with a prison sentence. You do not need to cause damage or copy anything: accessing is enough.
- Art. 264 and following: damaging, deleting, altering or rendering inaccessible someone else's data or systems, with aggravated penalties if critical infrastructure or a large number of systems are affected.
- Art. 197 ter: producing, supplying or possessing tools designed to commit those offences is also punishable when they are intended for that purpose.
Practical consequences: "I just wanted to try it out" is not a defence, the absence of damage does not remove the offence, an intrusive
nmapagainst a third party may already constitute an attempt, and the authorisation must be written, prior, signed by someone with the capacity to grant it and current on the date of the test. In the cloud you also need the provider's authorisation on top of the client's.That is why this lesson contains no exploits, no payloads and no exploitation commands. It describes the phases conceptually, shows the equivalent defensive verification and develops in detail how what was found is fixed. The complete ethical and legal framework — including responsible disclosure and the reasoning behind these rules — is developed in 06-06. (Note: the specific criminal classification depends on the case; whenever in any doubt, seek prior legal validation.)
Contents
- What a pentest is and what it is not
- Modes: black-box, grey-box and white-box
- Scope and rules of engagement
- The methodological phases
- What happens in each phase, and its defensive equivalent
- Walkthrough of an authorised test against Nimbus's environment
- The pentest report
- What happens afterwards: remediation and retest
- Responsible disclosure and bug bounty as a continuous alternative
- How to commission a pentest as a small company
- Where to practise legally
- What a pentest is and what it is not
A pentest is an authorised test in which a professional tries to compromise a system using the same techniques as a real attacker, with a declared objective and a report as the product. Its value does not lie in finding loose vulnerabilities — that is what 05-01 is for — but in demonstrating impact by chaining them together.
| Automated scan | Compliance audit | Pentest | Red team | |
|---|---|---|---|---|
| Question | What vulnerable versions do I have? | Do I meet the standard? | Can someone get in and how far do they get? | Do we detect and respond to a real adversary? |
| Method | Automated tool | Review of documents and evidence | Manual + tools, with creativity | Stealthy, multi-vector campaign, with social engineering |
| Duration | Hours | 1-3 weeks | 3-15 days | 1-3 months |
| Indicative cost (SME) | 0-1,500 €/year | 3,000-15,000 € | 4,000-15,000 € | 25,000 € or more |
| The team knows about it | Yes | Yes | Yes | No (only management) |
| What it measures | Known surface | Conformity | Real exploitability | Detection and response capability |
| When to choose it | Always, continuously | Certification or a customer requirement (06-04) | Before a launch, after a big change, or annually | Once you already have mature detection |
For Nimbus today, a red team would be throwing money away. It measures detection and response capability, and in 05-02 we have only just built the first twelve detections: you commission one once they have been running for a year. What is appropriate is an annual pentest of the application and the infrastructure, which is where the product and the risk live.
And one distinction worth being clear about: a pentest does not prove that a system is secure. It proves that, within a bounded period and a bounded scope, a specific person found these things. A report with no findings usually means the scope was narrow or the time was short, not that the system is impregnable.
- Modes: black-box, grey-box and white-box
| Black-box | Grey-box | White-box | |
|---|---|---|---|
| What the auditor receives | Only the domain name | User credentials and basic documentation | Source code, architecture, administrative credentials |
| Simulates | An external attacker with no information | A legitimate customer or an employee | A reviewer with full access |
| Time spent on reconnaissance | 30-40 % | 10 % | 5 % |
| Depth reached | Low: it stays at the perimeter | High in the business logic | Maximum, but furthest from a real attacker |
| Cost per finding | The highest | The lowest | Medium |
Grey-box gives the most value per euro, and in a multi-tenant SaaS the difference is enormous. The reason is direct: at Nimbus, the main risk is not a stranger getting in, it is a legitimate customer seeing another's data — the IDOR from 01-04 is exactly that. A black-box pentest would never have found it, because testing for it requires being inside with two accounts from two different tenants. Paying for somebody to spend three days discovering what an nmap gives you in ten minutes is a poor use of the budget.
Recommendation for Nimbus: grey-box with two test accounts from two different fictitious clinics plus a support-role account, and read access to the API documentation.
- Scope and rules of engagement
The rules of engagement are the document that turns an intrusion into a professional service. Without them, the test is legally fragile for both parties and operationally dangerous.
# SCOPE AGREEMENT AND RULES OF ENGAGEMENT
Client: Nimbus Reservas, S.L. Supplier: <auditor>
Valid: 2026-05-11 to 2026-05-22 Version: 1.1
## 1. Authorisation
Nimbus Reservas, S.L. expressly authorises the supplier to carry out security
testing against the assets listed in point 2, within the window in point 4.
Signed by Marta <surnames>, CTO, with capacity to grant this authorisation.
Cloud provider authorisation: requested and granted on 2026-05-04 (ref. XXXX).
## 2. Assets IN SCOPE
- preprod.nimbusreservas.example (SPA + API, preproduction environment)
- api-preprod.nimbusreservas.example and subdomains of *.nimbusreservas.example
- Mobile application (preproduction build, handed over to the auditor)
- Test accounts: clinica-alfa@, clinica-beta@, soporte-test@
## 3. Assets OUT OF SCOPE (absolutely excluded)
- Production (api.nimbusreservas.example and its database)
- Payment gateway and transactional e-mail provider (third parties: A-11, A-12)
- Systems belonging to the systems consultancy (A-19)
- Employees' personal devices and their e-mail accounts
- Any social engineering technique against staff (outside this contract)
## 4. Window and intensity
- Window: Mon-Fri 09:00-19:00 CEST. Outside the window: prohibited.
- Denial of service, load testing and mass brute force: PROHIBITED.
- Auditor rate limit: maximum 20 requests/second.
## 5. Data
- Downloading, copying or retaining real customer data is prohibited.
- On finding real data in preproduction: STOP, do not download, notify within
1 hour and document the fact only.
- All evidence is anonymised and delivered encrypted; it is destroyed after 30 days.
## 6. Stop condition
The supplier stops the test immediately if: (a) it causes unavailability,
(b) it accesses real personal data, (c) it finds indications of a PRE-EXISTING
compromise, or (d) Nimbus requests it through any channel in point 7.
## 7. Contacts
- 24/7 emergency: Lucia <phone> | Deputy: Marta <phone>
- Channel for critical findings: <secure channel>. Notice within < 2 h of the finding.
## 8. Critical findings raised in real time
A finding that allows access to customer data or control of the system is
reported IMMEDIATELY, without waiting for the final report, together with a
provisional mitigation recommendation.Five clauses deserve emphasis. Point 3 protects the auditor as much as the client: Nimbus cannot authorise testing against the payment gateway because it is not its own, and doing so would be exactly the offence in the opening warning. The cloud provider's authorisation (point 1) is mandatory and many people forget it: the provider has a testing policy and skipping it can get the account suspended. Point 5 is what stops an audit becoming a breach: if preproduction holds real data — remember A-22, "classification to be reviewed" — downloading it creates the very incident you wanted to prevent. Point 6c exists because it happens: sometimes the auditor finds that somebody is already inside, and at that point the test stops and the plan from 04-05 is activated. And point 8 is what separates a useful service from a posthumous report: if on day 2 somebody finds a way to read every clinic's data, you do not wait two weeks.
- The methodological phases
The recognised methodologies — PTES, OSSTMM and, for web applications, the OWASP Web Security Testing Guide (WSTG) — agree on the structure. The WSTG is also a public, free checklist: if you commission an application pentest, asking for WSTG coverage is the simplest way to compare offers.
flowchart TD
P["0. PREPARATION\nScope, rules,\nsigned authorisation"] --> R["1. RECONNAISSANCE\nPublic information:\nDNS, subdomains, leaks"]
R --> E["2. ENUMERATION\nPorts, services, paths,\nparameters, roles"]
E --> A["3. VULNERABILITY\nANALYSIS\nPrioritised hypotheses"]
A --> X["4. EXPLOITATION\nConfirm the impact\nwith minimum harm"]
X --> PX["5. POST-EXPLOITATION\nHow far you get:\npivot, data, persistence"]
PX --> I["6. REPORT\nThe real product\nand the handover meeting"]
I --> RT["7. RETEST\nVerify the fix\n(often skipped)"]
X -.->|"critical impact"| CE["Real-time notice\n(rule 8)"]
Two warnings about the diagram. The first: phase 4 is not the objective, it is the proof. Exploiting serves to show that the vulnerability is real and to measure its impact; a professional auditor exploits just enough to document it and then stops. The second: phase 7 is the one almost everybody skips, and without it you do not know whether you paid for a homework list nobody did.
- What happens in each phase, and its defensive equivalent
| Phase | What the auditor does | Typical tools | Your defensive verification |
|---|---|---|---|
| Reconnaissance | Gathers what is public: subdomains, DNS records, certificates, technologies, leaked credentials, team profiles | amass, certificate transparency, search engines |
Do it yourself first: enumerate your subdomains from the DNS zone and from the certificate logs (03-06), and switch off whatever is surplus |
| Enumeration | Maps the surface: ports, hidden paths, parameters, roles and application flows | nmap, ffuf, gobuster, ZAP in spider mode |
Review what paths your server exposes and remove panels and internal documentation reachable without authentication |
| Analysis | Formulates prioritised hypotheses: where authorisation, validation or configuration is most likely to fail | ZAP/Burp, testssl.sh, manual review |
Run testssl.sh and the scanner from 05-01; fix the obvious before the pentest so the auditor spends their time on what you cannot see |
| Exploitation | Confirms the hypothesis with the least possible harm and captures evidence | Frameworks like Metasploit for the known; almost everything at application level is manual | Nothing to do here beyond having verified backups (04-06) and warning the on-call person that the test is under way |
| Post-exploitation | Measures how far you get: pivoting to other networks, access to data, persistence | Tools native to the compromised environment | Measure your segmentation yourself with the connectivity tests in 05-04 |
| Report | Writes, prioritises and presents | — | Require the format in §7 in the contract |
On the tools named, with the precision this lesson's approach demands: nmap and testssl.sh are for reconnaissance and verification and you use them yourself daily; ZAP and Burp are intercepting proxies that let you see and modify the requests your own browser sends — their legitimate use is against your own application; ffuf and gobuster try lists of paths and files against your own server to discover what was published by accident; hydra tries credentials, and it has only one admissible use here: checking against your own test accounts that lockout after failed attempts and rate limiting work, which is a defensive verification; and Metasploit is a framework packaging exploitation modules for known vulnerabilities, whose use stays within the authorised scope and never in this material.
An observation that saves money: almost everything a pentest finds that is genuinely valuable in a SaaS is manual and about business logic. The IDOR, the password recovery flow that allows user enumeration, the reports endpoint that ignores the role. No tool automates that, and that is why you pay for hours of a person with judgement.
- Walkthrough of an authorised test against Nimbus's environment
Marta commissions five days of grey-box testing against preproduction, with the rules from §3. These are the five findings and their fixes.
6.1 Residual IDOR in the reports endpoint
The WHERE tenant_id was applied to the bookings and customers endpoints, but the reports module was written later and queries through an aggregate view that nobody reviewed. With the Alfa clinic's account, changing an identifier in the request returned the Beta clinic's billing totals.
# BEFORE - the filter depends on the developer remembering. In reports,
# nobody remembered: `tenant_id` comes from the parameter and not from the session.
@router.get("/informes/facturacion")
def billing(tenant_id: int, date_from: date, date_to: date, db=Depends(get_db)):
return db.execute(BILLING_VIEW, {"t": tenant_id, "d": date_from, "h": date_to})
# AFTER - the tenant NEVER comes from the client: it is derived from the verified
# token. This dependency is reused across every endpoint and makes failure by
# forgetfulness impossible, instead of relying on the discipline of whoever
# writes each route.
def current_tenant(current_user: User = Depends(get_current_user)) -> int:
return current_user.tenant_id
@router.get("/informes/facturacion")
def billing(date_from: date, date_to: date,
tenant_id: int = Depends(current_tenant), # <- from the session
db=Depends(get_db)):
return db.execute(BILLING_VIEW, {"t": tenant_id, "d": date_from, "h": date_to})The underlying fix is not the line that changed: it is that the customer identifier stops being an input parameter across the whole API. In addition, RLS was enabled on the aggregate view, which already protected the base tables but not the view (03-07). Generalising this pattern to the whole application is developed in 05-05.
6.2 Missing rate limit on log-in
The auditor confirmed that 4,000 authentication attempts could be sent in five minutes with no lockout and no slowdown: the door left open to the credential stuffing of 02-02.
# Shared 10 MB zone: ~160,000 IPs tracked. 5 requests/minute.
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
location /api/v1/auth/login {
limit_req zone=login burst=5 nodelay; # 5 of headroom without delaying legitimate ones
limit_req_status 429; # correct code: "too many requests"
proxy_pass http://api_upstream;
}And in the application, lockout per account as well as per IP, because password spraying uses a different IP for each attempt: after 10 failures against the same account in 15 minutes, a second factor is required or an exponential delay applied. Both feed detection D-01 from 05-02.
6.3 Missing security header
Content-Security-Policy was missing from the SPA, which turned any XSS into a complete session theft. It was deployed in report mode first so as not to break the application:
# Phase 1 (two weeks): does NOT block, it only reports what would break.
add_header Content-Security-Policy-Report-Only
"default-src 'self'; script-src 'self'; connect-src 'self' https://api.nimbusreservas.example;
frame-ancestors 'none'; report-uri /csp-report" always;After reviewing the reports and adjusting two legitimate origins, it was switched to Content-Security-Policy in blocking mode. The full set of headers and the reasoning for each is in 05-05.
6.4 Forgotten subdomain with obsolete TLS
Reconnaissance found pruebas-2019.nimbusreservas.example, served by a host that accepted TLS 1.0 and RC4 suites, and pointing at an IP that was no longer under Nimbus's control: a candidate for subdomain takeover (05-04).
TLSv1.0 offered (NOT ok)
TLSv1.1 offered (NOT ok)
TLSv1.3 not offered
ROBOT VULNERABLE
Certificate expired 412 days agoFix: delete the DNS record — do not patch a host that has to disappear, as we already concluded in 05-01 — and add a quarterly review of the DNS zone to the inventory.
6.5 Default credential on an internal panel
A queue administration panel, deployed "temporarily" eight months ago, answered at /flower with admin/admin and with no authentication on the proxy. From there you could see the identifiers and e-mail addresses of the jobs in flight.
# docker-compose.preprod.yml - BEFORE
flower:
image: mher/flower:latest
ports: ["5555:5555"] # published on the host's external interface
# AFTER
flower:
image: mher/flower:2.0.1 # pinned version, not `latest` (04-04)
ports: ["127.0.0.1:5555:5555"] # reachable only from the host itself
environment:
FLOWER_BASIC_AUTH: "${FLOWER_AUTH}" # credential from the secrets managerAccess now goes through an SSH tunnel via the bastion host. This finding is the most instructive of the five: it is not a software vulnerability, it has no CVE, no scanner from 05-01 would have flagged it as critical and it had been exposed for eight months. It is the same pattern as the python -m http.server: the temporary thing that stays.
- The pentest report
The report is the product. An auditor who delivers a tool dump with 80 unprioritised pages of output has not done the job, and that is the most reliable signal not to use that supplier again.
| Section | For whom | What it must contain |
|---|---|---|
| Executive summary | Marta | 1 page with no jargon: what was tested, what was achieved, the business risk and what decision is being asked for. If Marta needs help understanding it, it is badly written |
| Scope and limitations | Everyone | What was in, what was not, in which window and what could not be tested |
| Methodology | Technical staff and the auditor (06-04) | PTES/WSTG, phases covered, tools and versions |
| Findings | Lucía and Iván | One per record, with evidence, reproduction, CVSS and fix |
| Prioritised recommendation | Marta and Lucía | A plan in order of impact/effort, not an alphabetical list |
| Annexes | Iván | Full outputs, screenshots, requests |
### PT-2026-01 · Access to other customers' billing data (IDOR)
**Severity: Critical** · CVSS 8.1 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N)
**Asset:** api-preprod · endpoint `GET /api/v1/informes/facturacion`
**Status:** Reported in real time on 2026-05-12 at 11:40 (rule 8)
**Description.** The endpoint accepts the `tenant_id` parameter from the client
and does not check it against the tenant in the token. An authenticated user of
any clinic can read the billing aggregates of any other by changing a number.
**Reproduction.** (1) Authenticate as `clinica-alfa@` (tenant 41). (2) Call the
endpoint with `tenant_id=42`. (3) The response returns tenant 42's amounts.
Evidence: anonymised request and response in annex A.3.
**Impact.** Leak of financial information between competing customers and, by its
nature, a notifiable incident. The same pattern applied to the appointments
endpoints would expose health data (more serious still).
**Recommended fix.** Derive the tenant from the token through a dependency common
to the whole API and enable RLS on the aggregate view. Add an automated
tenant-isolation test to CI.
**Estimated effort:** 4 h of development + 2 h of testing.
**Retest verification:** repeat (1)-(3); expected response 403.The elements that make it actionable are the same as in 05-01, with two additions specific to a pentest: step-by-step reproduction — without it the developer cannot confirm the fix — and the retest verification criterion, which sets out in advance what will count as fixed.
- What happens afterwards: remediation and retest
The classic mistake is filing the report away. The correct cycle is short and has owners:
- Handover meeting with the auditor, Marta, Lucía and Iván. Each finding is discussed until the team understands it; a report that is e-mailed over and never explained loses half its value.
- A remediation plan with an owner and a date, using the deadline policy from 05-01: criticals in 7 days, highs in 30. Each finding becomes an issue with an acceptance criterion.
- Update of the risk register from 04-01. The residual IDOR is not a loose finding: it modifies risk R-04 (data leakage between customers), whose residual was calculated assuming control C-05 was implemented. It was half implemented, which is 04-03's lesson about implemented versus effective.
- Retest, included in the original contract and not as a separate service. It is a short exercise — usually one or two days — that only checks the findings that were fixed and produces an annex with the final status. Without a retest, the pentest measures the past.
- Structural lessons. If two IDORs turned up, the problem is not two lines: it is that authorisation is decided in each route. The structural fix — the common dependency — prevents the third one.
- Responsible disclosure and bug bounty as a continuous alternative
An annual pentest is a snapshot; external researchers are looking all year round. For an SME there are three steps, and the first is free and mandatory:
| Step | What it is | Cost | For Nimbus |
|---|---|---|---|
| Vulnerability disclosure policy (VDP) | One page saying how to report a flaw, what commitments you take on and that you will not pursue legal action against anyone researching in good faith. It is published at /.well-known/security.txt |
0 € | Do it now. Without it, whoever finds a flaw either does not know who to write to or fears being reported, and the flaw ends up somewhere else |
| Private bug bounty | Financial rewards to a small group of invited researchers | 3,000-10,000 €/year | Once the annual pentest stops finding criticals |
| Public bug bounty | Open to anyone, on a platform | 15,000 €/year or more | Out of scope today |
# https://nimbusreservas.example/.well-known/security.txt
Contact: mailto:seguridad@nimbusreservas.example
Expires: 2027-01-01T00:00:00.000Z
Preferred-Languages: es, en
Policy: https://nimbusreservas.example/seguridad/divulgacion
Acknowledgments: https://nimbusreservas.example/seguridad/graciasA management warning: a bug bounty without the capacity to respond is worse than not having one. If 40 reports arrive and nobody triages them within 48 hours, the community publishes it and the reputation (A-20) suffers more than it would from the original flaw. The ethics of disclosure, reasonable deadlines and the conflict between researcher and company are developed in 06-06.
- How to commission a pentest as a small company
What to ask for in the request for quotation, and it is five concrete things: a declared methodology (PTES or WSTG), the profile and named certifications of whoever will run it (not of the company), the actual person-days dedicated — the variable that determines quality — a retest included, and an anonymised sample report, which is the best predictor of what you will receive.
| Certification | What it attests | Signal |
|---|---|---|
| OSCP / OSWE | A practical 24-48 h exam compromising real machines | Very good: it is doing, not remembering |
| CREST (CRT, CCT) | Certification of the professional and of the company, with an audited process | Very good, particularly for the supplier |
| GPEN, GWAPT (SANS) | Solid training, theory-and-practice exam | Good |
| CEH | Broad knowledge, multiple-choice exam | Weak on its own |
Indicative price in Spain for an SME: 4,000-8,000 € for a web application with an API, grey-box, 5 person-days with a report and a retest; 8,000-15,000 € if cloud infrastructure and a mobile application are added. A reasonable cadence: annual, plus an additional test when there are major architectural changes (a new module with sensitive data, a change of identity provider, an infrastructure migration). With 18,000 €/year, Nimbus can afford an annual application pentest if it accepts that this is the largest single outlay in the budget, and the decision is defensible: A-04 is the product.
Three warning signs when comparing offers: a fixed price without knowing the scope, an "automated pentest" (that is a scan under another name and another price), and a refusal to hand over a sample report.
- Where to practise legally
Practising exploitation is necessary in order to understand the defence, and there is only one place to do it: environments designed for it.
| Environment | What it is | What for |
|---|---|---|
| OWASP Juice Shop | A modern, deliberately vulnerable web application; runs locally with Docker | Learning the OWASP Top 10 with a realistic application |
| DVWA | A PHP classic with difficulty levels | Seeing the same flaw with and without protection |
| TryHackMe | Guided walkthroughs with lab machines | Starting from scratch in a structured way |
| HackTheBox | Machines and labs of increasing difficulty | Intermediate and advanced level |
| VulnHub / your own environment | Vulnerable virtual machines on your own isolated network | Practising offline and without limits |
The rule, with no nuance: if the system is not yours and you have no written authorisation, it is not a lab. Your former employer's website is not one, nor is a supplier's that "will surely be grateful", nor a relative's. The labs in the table exist precisely so that there is never an excuse. And in a professional setting, that practice is also done on an isolated network, with snapshots and with no connection to the corporate network.
Common Mistakes and Tips
- Commissioning a pentest without written authorisation or rules of engagement. It exposes both parties legally and leaves no framework for what happens if something goes down.
- Choosing black-box for "realism". In a multi-tenant SaaS you pay for reconnaissance instead of depth, and the main risk — leakage between customers — goes untested.
- Testing against production unnecessarily. If preproduction is equivalent, you test there; and if it is not, fixing that difference is more urgent than the pentest.
- Not excluding third parties. You cannot authorise testing against the payment gateway or the consultancy: they are not yours.
- Contracting without a retest. Without verification, the report describes a system that no longer exists and nobody knows whether it was fixed.
- Treating findings as loose issues. Two IDORs are not two bugs: they are a design pattern in the authorisation.
- Tip: hand the auditor the results from 05-01. If you have already fixed what a scanner finds, their five days go on what no tool sees. It is the most direct way to multiply the value of what you are paying for.
- Tip: publish your
security.txttoday. It costs half an hour, it is free and it determines whether the next flaw somebody finds reaches your inbox or somewhere else. - Tip: warn your own on-call rota. With the detections from 05-02 live, a pentest will generate alerts. Them firing and being handled is, in fact, a free proof that detection works: record it as a verification.
Exercises
Exercise 1 — Fix a set of rules of engagement
A supplier sends this scope summary. Identify at least six problems and rewrite the affected clauses.
Scope: Nimbus Reservas infrastructure and applications.
Dates: May 2026. Hours: no restriction.
All Internet-accessible systems associated with the company will be tested,
including cloud services and connected suppliers.
The use of any technique is permitted, including telephone social engineering.
Findings will be delivered in the final report.
Contact: the sales representative's e-mail address.Exercise 2 — Decide the mode and the budget
In September Nimbus launches a teleconsultation module with video and clinical notes. Marta has 9,000 € for offensive security this year and asks what to commission.
- Pentest, red team, audit or bug bounty? Justify it.
- The specific mode and scope, including which accounts and what is excluded.
- How to allocate the 9,000 € and what is done with whatever is left.
Exercise 3 — Write up a finding and its fix
During the test, the auditor discovers that the password recovery flow answers "E-mail address not registered" when the address does not exist and "We have sent you a link" when it does, allowing an attacker to enumerate which e-mail addresses are customers of each clinic. In a SaaS used by physiotherapy clinics, knowing that an address is a customer is already sensitive information.
- Write up the finding record in the format from §7, assigning a severity with judgement.
- Write the fix in
python, explaining why it works. - State how it would be verified in the retest and which detection from 05-02 would cover it.
Solutions
Exercise 1
| # | Problem | Fix |
|---|---|---|
| 1 | "Infrastructure and applications": an indeterminate scope, impossible to contract and to defend legally | A closed list of domains, IPs and applications in scope, plus an explicit list of exclusions |
| 2 | "May 2026": the authorisation must have exact start and end dates | Window 2026-05-11 to 2026-05-22, with an express prohibition outside it |
| 3 | "Hours: no restriction": night-time testing with nobody on call; if something goes down, it stays down until the morning | Mon-Fri 09:00-19:00 CEST, with the on-call person warned |
| 4 | "Connected suppliers": this is the most serious clause. Nimbus cannot authorise testing against the gateway, the e-mail provider or the consultancy, and doing so would expose both parties to art. 197 bis | Absolute exclusion of third parties, and express authorisation from the cloud provider for what does belong to Nimbus |
| 5 | "Any technique, including social engineering": outside the contract, with no basis for processing staff data and with employment implications | Exclude social engineering or contract it separately, with prior notice and legal validation (06-06) |
| 6 | "Findings will be delivered in the final report": a critical found on day 2 would wait two weeks | A real-time notice clause: notification within 2 h for critical findings, with a provisional mitigation |
| 7 | Contact: the sales representative: not available 24/7 and does not know what to do | A technical emergency contact with a phone number and a deputy |
| 8 | Missing: a stop condition, handling of real data and an intensity limit | Add points 4, 5 and 6 of the template in §3 |
Exercise 2
(1) A pentest, without a doubt. A red team is ruled out because it measures detection and response, and the detections from 05-02 are months old, not years: it would measure a predictable failure at a very high price. A compliance audit answers a different question and will be dealt with in 06-04. A bug bounty demands a response capability Nimbus does not yet have. And the timing is right: a module with video and clinical notes is health data, it is a new surface and it is exactly when testing is worthwhile, before the launch and not after.
(2) Mode and scope. Grey-box, with two accounts from different clinics, a patient account and a support account, plus the documentation for the API and the video flow. Scope: the complete teleconsultation module (room creation, room access control, clinical notes, attachments and their field-level encryption from 03-07) plus the API endpoints it touches, in preproduction. Excluded: production, the video provider, the payment gateway, transactional e-mail and all social engineering. OWASP WSTG and API Top 10 coverage is requested (05-05), with two explicit questions for the auditor: can a patient get into somebody else's room? and can one clinic see another's notes?
(3) Allocation. ~6,500 € on 5 person-days of grey-box testing with a report and a retest included; ~1,000 € held back for a short second round if criticals appear that require a redesign; and ~1,500 € unspent until after the report. Whatever is left is not spent on more offensive work: it is spent on fixing. The industry's most expensive mistake is consuming the budget on finding and having nothing left to fix with. On top of that, free: publish the security.txt and run 05-01 against the module before the auditor arrives, so that their days go on the business logic.
Exercise 3
(1) Record:
### PT-2026-04 · User enumeration in password recovery
**Severity: Medium** · CVSS 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N)
**Asset:** api-preprod · `POST /api/v1/auth/recuperar`
**Description.** The response differs depending on whether the account exists,
which makes it possible to check in bulk and without authentication whether an
address belongs to a customer.
**Reproduction.** Send the request with a non-existent address and with a valid
one and compare body, status code and response time.
**Impact.** On its own it is low, but in a SaaS for physiotherapy clinics
**knowing that an address belongs to a patient of a specific clinic is already
health data by inference**, with the implications of art. 9 of the GDPR (06-03).
It also feeds credential stuffing (02-02) by confirming valid accounts.
**Fix.** An identical response in every case and a constant response time. Add
rate limiting per IP and per e-mail address.
**Retest verification:** 200 requests alternating valid and invalid addresses;
body, code and timing must be indistinguishable.The severity of Medium and not Low is the important judgement: the base CVSS treats it as a minor information leak, but the environmental group from 05-01 raises it because of the business context. That is precisely what a scanner cannot calculate.
(2) Fix:
@router.post("/auth/recuperar", status_code=202)
async def recover_password(data: RecoveryRequest, background: BackgroundTasks):
start = time.monotonic()
user = repo.find_by_email(data.email) # may or may not exist
if user:
# Sending happens in the background: its duration does not alter the response.
background.add_task(send_recovery_link, user)
else:
# The attempt is logged for the detection, but NOT disclosed outside.
log.info("auth.recover.unknown", extra={"fields": {"ip": ...}})
# Constant response time: without this, the attacker tells them apart by
# latency even if the message is identical. It is the side channel almost
# everybody forgets.
await asyncio.sleep(max(0, 0.35 - (time.monotonic() - start)))
# IDENTICAL message in both cases, and code 202 in both cases.
return {"message": "If the address is registered, you will receive a link."}It works because it removes all three channels through which the difference leaks: the message, the status code and the timing. The third is the one people forget: without the timing levelling, sending a real e-mail takes 300 ms longer and the attacker measures that difference precisely. The same reasoning applies to account registration and to changing an e-mail address, which are the other two places where this flaw reappears.
(3) Verification and detection. In the retest, 200 requests are sent alternating valid and invalid addresses and the body, the code and the distribution of times are compared: if the mean latency of the valid ones differs consistently, the finding is still open. The detection that covers it is a variant of D-01: more than 20 requests to /auth/recuperar from one IP in 5 minutes, or more than 100 distinct addresses tried in an hour, with severity S3 and automatic blocking through fail2ban — one of the actions 05-02 classified as safe to automate because they are reversible.
Conclusion
You now know what a pentest is and is not: an authorised test that demonstrates impact by chaining weaknesses, distinct from a scan (known surface), an audit (conformity) and a red team (detection capability), with its duration, its indicative cost and the criterion for choosing each one — and with the conclusion that for Nimbus today a red team would be throwing money away. You know that a pentest does not prove that a system is secure, and that a report with no findings almost always means a narrow scope or a short time. You know the three modes and why grey-box gives the most value per euro in a multi-tenant SaaS: the main risk is not a stranger getting in, but a legitimate customer seeing another's data, and that can only be tested from inside with two accounts.
You take away the template for a scope agreement and rules of engagement with its critical clauses: excluded assets — you cannot authorise testing against third parties — the cloud provider's authorisation, the window and the intensity, the prohibition on downloading real data, the stop condition for a pre-existing compromise, a 24/7 emergency contact and real-time notice of critical findings. You know the methodological phases of PTES/OSSTMM/WSTG and what happens in each, always with its defensive equivalent: enumerate your own subdomains, run testssl.sh, fix what a scanner sees before the auditor arrives and measure your segmentation yourself. And you know what saves money: what is genuinely valuable in a SaaS is manual and about business logic.
You have walked through a real authorised test against preproduction with its five findings and their fixes: the residual IDOR in reports, resolved by making tenant_id stop being an input parameter across the whole API; the missing rate limit, with limit_req in Nginx and per-account lockout for password spraying; the missing CSP, deployed in Report-Only first; the forgotten subdomain with obsolete TLS, which is deleted rather than patched; and the default credential on the queue panel, the most instructive finding because it has no CVE, no scanner would have prioritised it and it is the same pattern as the http.server: the temporary thing that stays. You know what the report must contain, how a finding is written up with step-by-step reproduction and a retest criterion, and why delivering a tool dump is the signal to change supplier. You know what happens afterwards: handover meeting, a plan with owners and deadlines, updating risk R-04 in the register from 04-01, a retest included in the contract and a structural fix instead of a one-off patch. And you know how to frame responsible disclosure — publish your security.txt today, it costs half an hour — and the bug bounty as a later step that should not be opened without a response capability, with the complete ethical and legal treatment waiting for you in 06-06. Finally, you know how to commission one: what to ask for, what OSCP and CREST attest, how much it costs, how often to do it and in which labs — Juice Shop, DVWA, TryHackMe, HackTheBox — exploitation is practised, which are the only place to practise it.
Notice how many of the five findings were, at bottom, network and exposure problems: a panel published on the host's external interface, a subdomain pointing at somebody else's IP, a service reachable from where it should not be. And remember what has been outstanding since 05-01: PostgreSQL listening on 0.0.0.0:5432, SSH open to the whole Internet and the consultancy with permanent access. In Network Security (05-04) we draw Nimbus's network as it stands, redesign it into zones, close those three holes with security groups and a bastion host, set up remote access with WireGuard, fix the guest wifi and the DNS, and — most importantly — check with connectivity tests that the segmentation really works, because an untested design is just a pretty drawing.
Fundamentals of Information Security Course
Module 1: Introduction to Information Security
- Basic Concepts of Information Security
- Types of Threats and Vulnerabilities
- Principles of Information Security
- Assets, Attack Surface and Threat Actors
Module 2: Cybersecurity
- Definition and Scope of Cybersecurity
- Types of Cyber Attacks
- Social Engineering and Phishing
- Protection Measures in Cybersecurity
- Identity, Authentication and Access Control
- Cybersecurity Incident Case Studies
Module 3: Cryptography
- Introduction to Cryptography
- Symmetric Cryptography
- Asymmetric Cryptography
- Hash Functions, HMAC and Password Storage
- Cryptographic Protocols
- Key Management, Certificates and PKI
- Applications of Cryptography
Module 4: Risk Management and Protection Measures
- Risk Assessment
- Security Policies
- Security Controls
- Third-Party and Supply Chain Risk
- Incident Response Plan
- Disaster Recovery and Business Continuity
Module 5: Security Tools and Techniques
- Vulnerability Analysis Tools
- Monitoring and Detection Techniques
- Penetration Testing
- Network Security
- Application Security
- System Hardening and Endpoint Security
- Cloud and Container Security
Module 6: Best Practices and Regulations
- Best Practices in Information Security
- Security Regulations and Standards
- Personal Data Protection and GDPR in Practice
- Compliance and Auditing
- Training and Awareness
- Ethics, Legal Aspects and Responsible Disclosure
