The previous two lessons were an inventory of the problem: the technical attacks ordered by phase of the chain, and the human vector with all its variations. This lesson is the inventory of the response. We are going to work through the catalogue of defences that counters what you have seen, organised by the layers of defence in depth you established in 01-03: perimeter and network, endpoint, data, application and development life cycle, and logging and observability. For each measure you will see what it does, when it is used and which specific attack it neutralises; the detailed implementation belongs to module 5 and is only linked to here. And because Nimbus's budget is not infinite, the lesson ends with the most useful thing of all: a table of the twelve highest-return measures with their cost, effort and impact, and a phased 30, 90 and 180-day plan that Marta could approve on Monday.

Contents

  1. How to choose defences: three criteria before spending a euro
  2. Perimeter and network protection
  3. Endpoint protection
  4. Data protection
  5. Protecting the application and the development life cycle
  6. Logging and observability as a protection measure
  7. Prioritising on an SME budget: the 12 highest-return measures
  8. Phased plan: 30, 90 and 180 days

  1. How to choose defences: three criteria before spending a euro

Before the catalogue, the method. The most common way of spending badly on security is buying what is advertised rather than what is missing.

Criterion 1: which specific attack does it neutralise? Every measure must be traceable to an entry in the summary table of 02-02 or in the catalogue of 02-03. If you do not know which attack it stops, you do not know whether you need it.

Criterion 2: which phase of the chain does it act on, and what other layers do I already have there? Remember the Kill Chain from 02-01: if all your measures act on the same phase, you have a defence that is thick on one side and bare on the other.

Criterion 3: what type of control is it? Controls are classified by function, and a healthy defence has all four types:

Type What it does Example at Nimbus
Preventive Stops it happening MFA, parameterised queries, firewall
Detective Warns that it is happening Mass export alert, audit log
Corrective Reduces the damage or restores Restoring backups, revoking tokens
Deterrent Discourages the attempt Legal banner, notice that the session is recorded

The typical imbalance you already diagnosed with the NIST CSF in 02-01: almost everything preventive, almost nothing detective. It is comfortable because preventive controls are bought and installed once, whereas detective ones require somebody to look. But when prevention fails — and it will — the only thing that limits the damage is detection.

A fourth criterion, informal but decisive in an SME: does this measure survive a bad day? A defence that demands ten minutes of daily discipline from somebody who is already swamped will not last three weeks. The measures that work at Nimbus are the ones that are on by default, automated or in the natural path of the work.


  1. Perimeter and network protection

The classic perimeter has lost weight — half the headcount works remotely and the data is in the cloud — but it has not disappeared: it is still the first line against the mass scanning of 02-02.

2.1 Firewalls: which type is needed and what for

Type What it inspects What it stops Where it fits at Nimbus
Packet filtering IP, port, protocol Access to services that should not be reachable The cloud provider's security groups; it is what was missing on the 0.0.0.0/0 for port 22
Stateful The above + the state of the connection Packets that do not belong to an established connection Standard in any modern firewall
Next-generation (NGFW) Application and identity, not just port Legitimate traffic over port 443 but towards inappropriate destinations The Valencia office router
Web application (WAF) HTTP requests: body, parameters, headers SQL injection, XSS, path traversal, bots In front of the API (A-04)

On the WAF, precisely, because it is the most misunderstood measure of all: a WAF buys time, it does not fix code. It is extraordinarily useful for three things: holding back the automated background noise, applying a virtual patch while a newly discovered vulnerability is being fixed, and providing visibility of what is being attempted against the API. What it does not do: replace parameterised queries or detect an IDOR, because an IDOR request is perfectly well formed. If Nimbus installs a WAF and relaxes code review as a result, it has made things worse.

2.2 Segmentation

What it is. Dividing the network into zones with control between them, so that compromising one does not give access to the others.

flowchart TB
    INT["INTERNET"] --> DMZ["PUBLIC ZONE\nLoad balancer + WAF"]
    DMZ --> APP["APPLICATION ZONE\nAPI, workers\nNo direct access from the Internet"]
    APP --> DAT["DATA ZONE\nPostgreSQL, Redis\nReachable only from the application zone"]
    OFI["VALENCIA OFFICE\nCorporate wifi"] -->|"only via bastion + MFA"| APP
    INV["GUEST WIFI\nIsolated, no internal access"] --> INT
    CONS["EXTERNAL CONSULTANCY"] -->|"just-in-time access, with expiry"| APP

Why it is the most cost-effective measure against ransomware. The timeline in 02-02 showed the attacker spending days moving laterally. Segmentation is what turns "they got into a laptop" into "they got into a laptop" rather than "they encrypted the whole infrastructure". Three practical rules for Nimbus:

  • The guest wifi touches nothing internal. It is a five-minute control on the router and it removes a whole class of risk.
  • The data zone only accepts connections from the application zone. Never from the office and never from the Internet. You already checked this with describe-security-groups in 01-04.
  • Administrative access always goes through a single point (a bastion host or a VPN with MFA), which is then the only place that really needs watching.

2.3 Anti-DDoS protection

Against the volumetric kind, the defence is bought in: the cloud provider or a CDN absorbs the traffic before it reaches Nimbus's link. It is one of the few defences that genuinely cannot be built with your own resources, because it requires network capacity.

Against the application-layer kind, the defence is programmed, and you already saw it in 02-02: mandatory pagination, business range limits, rate limiting and a maximum query time. No anti-DDoS service tells an expensive request from a cheap one: to it, both are a legitimate HTTPS request.

2.4 VPN and secure remote access

With 19 people outside the office, remote access is Nimbus's perimeter.

Model How it works Advantage Problem
Traditional VPN The machine joins the internal network and reaches everything Simple and familiar "All or nothing" access: one compromised credential gives away the whole network. It is the Colonial Pipeline case we will see in 02-06
Bastion / jump host A single jump point with MFA and logging One point to watch and audit Requires discipline in use
Zero Trust access per application Authorisation is granted application by application, verifying identity and device state on every request There is no "inside"; a compromise does not hand over the network Higher initial configuration cost

Recommendation for Nimbus: mandatory MFA on remote access (no exceptions, including the consultancy), a bastion host with session logging for administrative access, and just-in-time access with an expiry for third parties instead of the current permanent access of asset A-19. The identity detail goes in 02-05; the network configuration, in 05-04.


  1. Endpoint protection

The 40 laptops (A-14) are where people work, and therefore where the phishing of 02-03 lands.

3.1 Antivirus versus EDR

Aspect Traditional antivirus EDR (endpoint detection and response)
Detects by Signatures of known files Behaviour: what a process does, who it talks to, what it modifies
Covers Known malware Fileless attacks, misuse of legitimate tools, lateral movement
Provides Blocking Blocking + telemetry and history for investigation
Allows Remotely isolating a compromised machine
Cost Low Medium; it requires somebody to attend to the alerts

Why the difference matters in the Nimbus case. Look back at exercise 3 of 02-03: Rubén's laptop runs a component that establishes an outbound channel and steals the browser cookie. A signature-based antivirus may see nothing, because the file is new and because much of the activity uses legitimate system tools. An EDR sees the pattern: an office process launching a command interpreter, an access to the browser's credential store, an outbound connection to a recently registered domain. And, above all, it allows the machine to be isolated with one click and lets you reconstruct afterwards what happened.

The realistic warning: an EDR whose alerts nobody looks at is an expense, not a defence. Before buying it, you have to decide who attends to it and when. For Nimbus, the sensible option is usually an EDR with a managed monitoring service, or a well-configured EDR with few, highly actionable alerts.

3.2 The other three endpoint measures

Measure Which attack it stops Practical detail for Nimbus
Full disk encryption Theft or physical loss of a laptop Enabled on all 40 machines, with centralised custody of the recovery keys. Without custody, an employee who forgets their key causes a self-inflicted data loss
Patch management Exploitation of known vulnerabilities — the vector of WannaCry and Equifax (02-06) Automatic operating system and browser updates; a committed deadline for critical ones (7 days is a reasonable target); an inventory that shows which version each machine has
Application control Execution of unauthorised software, including the baiting USB stick Allow only approved applications; block macros from external sources; block execution from temporary folders and from removable devices

The most underrated of the three is patching. It is not glamorous, it cannot be shown to a customer and it appears in no sales brochure. But two of the biggest incidents in recent history — the ones we will analyse in 02-06 — were known vulnerabilities with a patch available for months. Hardening and endpoint management are studied in detail in 05-06.


  1. Data protection

The previous layers protect containers. This one protects what is inside, and it is the only one that still helps when the others fail.

4.1 Classification: the prerequisite

You cannot protect differently what has not been classified. You already did it in 01-04 with the four levels (public, internal, confidential, restricted) and their three rules: inheritance upwards, aggregation raising the level, and context defining sensitivity. Classification is not a measure in itself: it is what makes it possible to apply everything else without going bankrupt.

4.2 Encryption in transit and at rest

Where What it protects State at Nimbus
In transit, external Eavesdropping between the client and the API TLS 1.3 with HSTS: done
In transit, internal Eavesdropping on the private network (flow F3 of the DFD) Outstanding: TLS between the load balancer and the API as well
At rest, database Access to the disk or the volume Volume encryption with managed keys: done
At rest, bucket Access to the object storage Server-side encryption with a managed key: done
At rest, backups Theft of a backup Critical: the backup contains everything. Encrypted and with a key different from production's
At field level Legitimate database access that should not see certain fields Worth considering for the most sensitive fields

Two clarifications that prevent false senses of security:

  1. The provider's encryption at rest protects against theft of the physical medium, not against an attacker with valid credentials. If the attacker has access to the database, the engine returns the data decrypted: that is what the key is for. It does not protect against an IDOR, nor against ransomware operated with stolen credentials.
  2. The key is the real asset. Encrypting with a key that sits in the same place as the data is a decorative exercise. Key management — where the keys live, who has access, how they are rotated — is the hard problem, and it is studied in 03-06.

The cryptographic mechanisms are developed in module 3; what matters here is where to apply them.

4.3 Backups: the 3-2-1 rule and immutability

This is the most important measure in the whole lesson, because it is the only one that gives the business back when everything else has failed.

The 3-2-1 rule:

  • 3 copies of the data (production and two more).
  • On 2 different media or technologies.
  • 1 of them out of reach of the main infrastructure.

The modern extension, 3-2-1-1-0, which is the one that matters against ransomware:

  • 1 copy that is immutable or offline.
  • 0 errors in the restore test.

Why immutability is the decisive piece. Remember the ransomware timeline from 02-02: on day 20, before encrypting, the attacker deletes the backups. If Nimbus's backups sit in the nimbus-backups-prod bucket (A-03), inside the same cloud account (A-05) and reachable with the same credentials as production, then they are not backups: they are more files that are going to be encrypted.

Target configuration for Nimbus:

Requirement Implementation
Separate account The backups go to a different cloud account, with credentials production does not know
Immutability Object lock in compliance mode, with 30-day retention: nobody, not even the administrator, can delete them before then
Encryption With its own key, different from production's
Verification A full, timed restore every quarter, with the result documented
Scope Database, attachments bucket, infrastructure configuration and secrets (often forgotten)

The sentence worth internalising: a backup that has never been restored is not a backup, it is a hope. The most common form of failure is not that the backup is missing: it is that the backup existed but was corrupt, incomplete, or nobody knew the procedure. Continuity and recovery time objectives are developed in 04-06.

4.4 DLP, minimisation and pseudonymisation

Measure What it does Application at Nimbus
DLP (data loss prevention) Detects and blocks sensitive data leaving by e-mail, web or USB Realistic for Nimbus in a light version: alert if a file with many DNIs or e-mail addresses goes out; block USB write access
Minimisation Not collecting or keeping what is not needed Does Nimbus need patients' DNI (the Spanish national ID number)? Does it need to keep the appointment history for five years? What is not there cannot leak
Pseudonymisation Replacing identifiers with references reversible only with separately held information The pre-production environment (A-22) must use pseudonymised data, never a direct copy of production
Anonymisation Irreversible transformation For aggregate metrics and usage statistics
Retention and deletion Removing data when it is no longer needed A written policy per data type and automated deletion

Minimisation is the measure with the best cost/benefit ratio in this section, and it is almost never applied because it requires saying no to data that "might be useful one day". Data that does not exist does not leak, does not have to be encrypted, does not have to be audited and does not appear in a breach notification.

Note on legal implications: minimisation, pseudonymisation, retention periods and deletion carry specific regulatory requirements, especially when the data can reveal health information, as is the case with clinic diaries. The decisions must be validated with the compliance owner or with legal advice; the handling is covered in 06-03.


  1. Protecting the application and the development life cycle

The API (A-04) is Nimbus's main surface. This layer shifts security to the left: to the moment the code is written, where fixing is cheap.

5.1 Code review and automated analysis

Practice What it finds Cost
Peer review with a security perspective Authorisation logic, design decisions, things no tool sees (the IDOR) Nothing extra if changes are already reviewed
SAST (static analysis) Dangerous patterns in the code: SQL concatenation, verify=False, pickle.loads Low; initial noise that has to be tuned
SCA (composition analysis) Dependencies with known vulnerabilities Low; the one with the highest immediate return
Secret scanning Credentials in the code and in the history Very low; essential after the token finding of 01-04
DAST (dynamic analysis) Flaws visible by attacking the running application Medium; useful in pre-production

The four-question checklist Iván should apply on every review, already introduced in 02-02:

  1. Who are you? — does the endpoint require authentication?
  2. Is it yours? — is it filtered by tenant_id and is ownership of the resource verified?
  3. Is what you are sending valid? — is there type and range validation?
  4. How much does this cost? — is there pagination, are there limits and rate limiting?

5.2 Secrets management

The finding of the non-expiring token in 01-04 and the leaked .env in the chained attack of 02-02 have the same root: secrets live where they should not.

Rule Why
Never in the code or in the repository Git keeps the history: deleting the file does not delete the secret
In a secrets manager, with logged access A single place to audit and rotate
Injected at run time, not into the container image An image with secrets is a secret published in the registry
Short-lived wherever possible Cloud provider credentials with a life of minutes instead of permanent keys
Rotatable without deploying If rotating requires a deployment, it will not get rotated
On detecting an exposure: rotate first, investigate afterwards The other way round is the classic mistake

5.3 HTTP security headers

A set of instructions to the browser that takes a few minutes to configure and neutralises whole classes of attack from section 6 of 02-02.

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self';
    img-src 'self' data:; connect-src 'self' https://api.nimbusreservas.example;
    frame-ancestors 'none'; base-uri 'none'; form-action 'self';
    report-uri https://csp.nimbusreservas.example/informe
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()
Cache-Control: no-store

An explanation of each one, and which attack it stops:

Header What it does Attack it neutralises
Strict-Transport-Security Forces the browser to use HTTPS for 2 years, including subdomains, and not to allow a manual exception Downgrade to HTTP and interception (02-02, section 3)
Content-Security-Policy Declares where each type of resource may be loaded and executed from XSS: even if code is injected, the browser refuses to run it
frame-ancestors 'none' Stops another website embedding the page in a frame Clickjacking
X-Content-Type-Options: nosniff Stops the browser guessing the content type Uploaded files interpreted as executable code
Referrer-Policy Limits the information sent when navigating to another site Leakage of identifiers and internal paths in the Referer header
Permissions-Policy Disables browser features the application does not use Surface reduction on the client
Cache-Control: no-store Stops responses containing personal data being cached Recovery of data on a shared machine

Details of the CSP that make the difference:

  • default-src 'none' as the base. You start from "nothing allowed" and open up only what is strictly necessary. It is the secure by default principle from 01-03 applied to the browser.
  • No 'unsafe-inline' and no 'unsafe-eval'. Allowing them cancels most of the CSP's value against XSS. It requires the JavaScript to be in files, not inline.
  • report-uri turns the CSP into a detective control: every violation is logged. A spike in CSP reports is usually the first sign of an XSS attempt. It is best deployed first in report-only mode (Content-Security-Policy-Report-Only) so as not to break the SPA.

5.4 Rate limiting

It has appeared in every section, and for one reason: it is the measure that takes the profit out of most automated attacks — brute force, enumeration, mass export, application-layer DDoS, business logic abuse.

Dimension of the limit What for
Per IP Automated noise; not very effective against distributed attackers
Per user or token Enumeration and mass export; the most useful one in an API
Per tenant Stopping one customer consuming everyone else's capacity
Per sensitive operation Log-in, password reset, export: far stricter limits

The AppSec details are developed in 05-05.

5.5 A CI workflow with dependency and secret scanning

This is the file Iván would add to the Nimbus repository. It is explained step by step afterwards.

name: security
on:
  push:
    branches: [main]
  pull_request:
  schedule:
    - cron: "0 6 * * 1"          # Mondays at 06:00: periodic review

permissions:
  contents: read                  # least privilege: the workflow only reads the code

jobs:
  analysis:
    runs-on: ubuntu-latest
    steps:
      # 1. Checking out the code. The action is pinned by hash, not by tag.
      - name: Check out code
        uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
        with:
          fetch-depth: 0          # full history: needed to search for
                                  # secrets in old commits

      - name: Set up Python
        uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38
        with:
          python-version: "3.12"

      # 2. Dependencies with known vulnerabilities (SCA)
      - name: Dependency scanning
        run: |
          pip install pip-audit
          pip-audit --requirement requirements.txt \
                    --format json --output audit.json || true
          pip-audit --requirement requirements.txt \
                    --vulnerability-service osv --strict
        # --strict returns an error code if there are vulnerabilities:
        # that way the build FAILS and nobody can ignore it

      # 3. Secrets in the code and in the WHOLE history
      - name: Secret scanning
        uses: gitleaks/gitleaks-action@83373cf2f8c4db6e24b41c1a9b086bb9619e9cd3
        env:
          GITLEAKS_CONFIG: .gitleaks.toml

      # 4. Dangerous patterns in our own code (SAST)
      - name: Static analysis
        run: |
          pip install bandit
          bandit -r app/ -ll -f screen
        # -ll: medium and high severity only, so the signal is not drowned out

      # 5. Component inventory (SBOM): answer "what do we use?" in minutes
      - name: Generate SBOM
        run: |
          pip install cyclonedx-bom
          cyclonedx-py requirements -i requirements.txt -o sbom.json

      - name: Store results
        if: always()              # stored even if a step has failed
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
        with:
          name: security-reports
          path: |
            audit.json
            sbom.json

The seven decisions in this file, explained:

  1. permissions: contents: read. By default, many workflows receive broad permissions. Declaring the minimum stops a compromised action writing to the repository. It is least privilege (01-03) applied to CI.
  2. Actions pinned by commit hash, not by @v4. A tag can be repointed at other code; a hash cannot. It is the defence against the supply chain attack of 02-02.
  3. fetch-depth: 0. Without the full history, the secret scan only looks at the last commit and misses exactly what has to be found: the credential somebody uploaded and "deleted" eight months ago.
  4. --strict in the dependency scan. Without it, the report gets generated and nobody reads it. With it, the build fails and a decision has to be made: update, or justify the exception in writing. An analysis that cannot block does not change behaviour.
  5. -ll in the static analysis. Filtering by severity is what avoids the usual fate of these tools: 400 warnings, nobody looks at them, the tool gets switched off.
  6. SBOM. When the next critical vulnerability in a famous library comes out, the question will be "does it affect us?". With an SBOM that is answered in minutes; without one, in days. It is the 01-04 inventory applied to software.
  7. if: always() when storing results. The reports from the day something fails are precisely the ones you need to keep.

And a warning about what this workflow does NOT do: it does not find the IDOR, it does not find business logic abuse and it does not find an authorisation design flaw. Automated tools cover the known patterns; human judgement covers the rest. Complementary, not substitutes.


  1. Logging and observability as a protection measure

The CSF diagnosis in 02-01 was clear: Nimbus's weakest function is Detect. And without logging there is no possible detection.

6.1 What to log

Category Events Why
Authentication Successful and failed log-ins, MFA, log-outs, password changes Detects password spraying, stuffing, anomalous sessions (02-02)
Authorisation Access denials, use of administrative functions, customer impersonation Detects escalation and IDOR
Access to sensitive data Queries and exports with actor, tenant and volume This is what detected the exfiltration in the 02-02 exercise
Configuration changes Permissions, network rules, roles, bucket policies Detects attacker persistence
Account life cycle Joiners, leavers, role changes, token creation Detects accounts created by the attacker
Application events 5xx errors, SQL errors, CSP violations Early signals of an exploitation attempt
Infrastructure SSH access, container execution, image changes Lateral movement

The five fields every useful event must have: when (with time zone and a synchronised clock), who (a named identity, not "admin"), what (the specific action), on what (resource and tenant) and from where (IP and agent). A log with no identifiable actor is useless for investigation; a log with no resource is useless for measuring the scope.

6.2 What must NEVER be logged

This section is as important as the previous one, because a badly designed log creates a security problem instead of solving one.

Never log Why
Passwords, not even failed ones A failure is usually a real password mistyped, or one from another service
Tokens, API keys, session cookies A log with tokens is a file of valid credentials, and logs are copied and shared readily
Data revealing health information The service name of an appointment ("knee rehabilitation") must not appear in an application log
Full card or account numbers Specific obligations apply; at Nimbus payments are tokenised at the gateway precisely so as not to touch them
Full request and response bodies It is the most common way of leaking all of the above without realising
Identity documents and unnecessary personal data Minimisation applies to logs too
# === BAD: logs the full body, including personal data and tokens ===
logger.info("Request received: %s headers=%s body=%s",
            url, dict(request.headers), await request.body())

# === GOOD: log what is needed to investigate, and nothing more ===
logger.info(
    "access",
    extra={
        "user_id": current_user.id,        # identity, not full name
        "tenant_id": current_user.tenant_id,
        "action": "export_bookings",
        "resource": "bookings",
        "record_count": len(rows),         # the VOLUME is the alerting signal
        "ip": request.client.host,
        "session_id": session.id,
        # no patient names, no token, no request body
    })

Why this version makes detection possible and the previous one does not: the record_count field, together with session_id and tenant_id, is exactly what made the detection query in exercise 3 of 02-02 work. Detection is designed when the log is written, not when the incident happens. And the correct log contains fewer personal data than the incorrect one, not more.

6.3 The three properties that make a log useful

  1. Centralised. Logs spread across five machines cannot be correlated. What is more, an attacker who compromises a machine deletes its local logs: shipping them off the box in real time is what preserves the evidence.
  2. Intact and retained. The append-only audit table from 01-01 — with INSERT but without UPDATE or DELETE for nimbus_api — is this idea in practice. Minimum advisable retention: 90 days hot, one year cold. Many breaches are discovered months later, and without logs the scope cannot be determined, which is exactly what has to be communicated to customers and authorities.
  3. With alerts somebody attends to. A log with no alerts is a historical archive. Few alerts and very good ones: for Nimbus, five initial rules are enough.

The five alerts to start with tomorrow:

Alert Initial threshold Attack it detects
Authentication failures from one origin against several accounts > 5 distinct accounts in 10 min Password spraying
Anomalous data export > 5,000 records or > 3 tenants per session/hour Exfiltration
Use of an administrative function outside working hours Any between 22:00 and 07:00 Compromise of a privileged account
Change to network rules, IAM permissions or bucket policies Any not originating in CI Attacker persistence
Creation of a token, SSH key or new account Any Persistence

Monitoring and detection techniques are developed in 05-02.


  1. Prioritising on an SME budget: the 12 highest-return measures

Nimbus cannot do everything. This is the table that turns the catalogue into decisions. Cost is money, effort is the team's time, impact is real risk reduction.

# Measure Cost Effort Impact What it neutralises
1 Phishing-resistant MFA on all administrative accounts (cloud, GitHub, mail, DB, VPN) Low Low Very high Spraying, stuffing, credential phishing, the consultancy's access
2 Immutable backups in a separate account + quarterly restore test Low-medium Medium Very high Ransomware, accidental or malicious deletion
3 Closing the surface found (SSH 0.0.0.0/0, Redis without auth, http.server, node_exporter, dead subdomains) None Low Very high Automated opportunistic attack
4 Expiry and minimal scope on all tokens + rotation of the deployment token None Low High The chained attack of 02-02
5 Dependency and secret scanning in CI (the yaml from section 5.5) None Low High Vulnerable dependencies, leaked secrets
6 Centralised logging + the 5 alerts from section 6.3 Low Medium Very high Everything that is invisible today
7 SPF -all, DKIM and DMARC p=reject + external e-mail banner None Low-medium High Domain spoofing, CEO fraud
8 Payment verification and support identity verification procedures None Low High BEC, IBAN fraud, vishing
9 Patch management with a committed deadline (7 days for critical ones) Low Medium High WannaCry, Equifax and their equivalents
10 Disk encryption on the 40 laptops with key custody None Low Medium-high Laptop theft or loss
11 Minimal segmentation: isolated guest wifi, closed data zone, bastion with MFA Low Medium High Lateral movement, ransomware
12 EDR on the laptops with somebody attending to the alerts Medium Medium High Malware, session theft, lateral movement

Three observations about this table:

  • Eight of the twelve measures have zero or low financial cost. What Nimbus lacks is not budget: it is decision and allocated time. It is the most repeated conclusion in SME security and the hardest one to accept.
  • The only one with a real medium cost is the EDR (#12), and it comes last on purpose: without MFA, without immutable backups and without logging, an EDR is a badly placed luxury.
  • None of the twelve is a perimeter security product. There is no new firewall on the list, and that is not an oversight: Nimbus's risk is not there.

  1. Phased plan: 30, 90 and 180 days

flowchart LR
    F1["DAYS 1-30\nURGENT\nClose what is open,\nMFA, tokens,\nimmutable backups"]
    F1 --> F2["DAYS 31-90\nSTRUCTURAL\nLogging and alerts,\nsecurity CI,\nmail and processes"]
    F2 --> F3["DAYS 91-180\nMATURITY\nSegmentation, EDR,\nformal patching,\nrecertification"]
    F3 --> F4["ONGOING\nQuarterly review,\nsimulations, restore\ntests"]

Phase 1 — Days 1 to 30: stop the bleeding

Everything that can be done with no budget, no supplier and no project.

Task Owner Verification that it is done
Close SSH to 0.0.0.0/0; access only through the bastion Lucía describe-security-groups with no 0.0.0.0/0 on administrative ports
Shut down the http.server, isolate the forgotten NAS, withdraw the public node_exporter and snmpd Lucía ss -tulpn showing only the intended services
Authenticate Redis and bind it to the private network Lucía Connection from outside refused
Mandatory MFA on cloud, GitHub, mail and VPN, including the consultancy Marta Report of accounts without MFA: empty
Rotate the nimbus-deploy-bot token; minimal scope and expiry Marta No token without an expiry date
Revoke the public link to the payroll sheet and review accesses Sara Link inaccessible; log reviewed
Backups to a separate account with a 30-day object lock Lucía Deletion attempt refused by the provider itself
One full, timed restore Lucía Document with time taken and result
External e-mail banner Marta Visible in a test e-mail
Payment verification procedure, signed Sara + Marta One-page document published
Phishing reporting channel communicated to all 38 Sara Test report completed

Phase 2 — Days 31 to 90: build capability

Task Owner Expected outcome
Centralised logging with the fields from section 6.1 Lucía All authentication and data access events in a single place
The 5 initial alerts, with a rotating on-call Lucía Each alert with an owner and a one-line procedure
The security CI workflow from section 5.5 Iván A build that fails on a high-severity vulnerability
Fix whatever the first scan reveals Iván Zero outstanding critical vulnerabilities
SPF to -all, DKIM and DMARC at p=none with reports Lucía rua reports received and senders identified
HTTP security headers, CSP in report mode Iván Headers present; CSP reports collected
Rate limiting on authentication, export and expensive endpoints Iván Load test confirming the limit
TLS on the internal hop (flow F3) Lucía No internal traffic in the clear
Identity verification procedure in support Rubén + Marta Document plus a rehearsal with real cases
First phishing simulation with metrics Sara Report rate and time to first alert measured
Disk encryption on the 40 laptops with key custody Lucía Inventory at 100 %

Phase 3 — Days 91 to 180: maturity

Task Owner Expected outcome
DMARC to p=quarantine and then p=reject Lucía Domain protected against spoofing
CSP in blocking mode Iván No regressions in the SPA
Segmentation: guests isolated, data zone closed, bastion Lucía Network diagram updated and verified
EDR deployed, with a defined alert owner Lucía 100 % laptop coverage
Patch management with deadlines and measurement Lucía Dashboard with patch age per machine
Just-in-time access with expiry for the consultancy (A-19) Marta Permanent access removed
First access recertification Marta Access list reviewed and signed off
Pre-production with pseudonymised data Iván Classification of A-22 resolved (no longer "to be reviewed")
Second restore test, timed Lucía Recovery time known and documented
First external penetration test Marta Report with a prioritised remediation plan

How this is sustained over time: a one-hour quarterly review looking for what is left over (01-04), one simulation per quarter, one restore test per quarter and an access recertification every six months. Four routines, all of them in the calendar. What is not scheduled does not happen.

Note: the deadlines in this plan are indicative and must be adjusted to each organisation's reality. The formal obligations of policy, documented control and auditable evidence are covered in 04-02, 04-03 and 06-04.


Common Mistakes and Tips

Common mistakes:

  • Buying before closing. Acquiring a WAF or an EDR while SSH is open to the Internet is investing in the roof with the foundations unfinished.
  • Relying on the WAF so as not to fix the code. The WAF buys time; it does not fix an injection and it does not see an IDOR.
  • Calling something a backup when it has never been restored. The most common failure is not the absence of backups but their uselessness at the moment of truth.
  • Keeping the backups in the same account and with the same credentials as production. Modern ransomware looks for them and deletes them: that is not a backup.
  • Logging full request bodies. It turns the logging system into a store of tokens and personal data, and multiplies the impact of any leak.
  • Generating a hundred alerts nobody looks at. Worse than having no alerts, because it produces a feeling of coverage.
  • Deploying CSP straight into blocking mode. It breaks the SPA and ends up switched off forever. Report mode first.
  • Leaving the CI analysis with no ability to block. A report that stops nothing changes nobody's behaviour.
  • Encrypting and considering it solved. Encryption at rest does not protect against stolen credentials or against an authorisation flaw.
  • Writing the plan with no owner and no date. A task with no name and no day is an intention.

Tips:

  • Always start with point 3 of the table: close what is already open. Zero cost, maximum impact, and it reduces future work too.
  • For every measure you put in place, write down how you would check that it is still working in six months' time. Defences degrade silently.
  • Prefer what works by default over what demands daily discipline. In a 38-person company, discipline runs out; configuration stays.
  • When torn between two measures, pick the one that reduces the damage of a failure over the one that tries to prevent one more failure. The first works even when you get things wrong.
  • Turn every incident and every simulation into one new alert. It is the zero-cost purple team from 02-01.
  • Review the phased plan with Marta every 30 days, ticking off what is done and renegotiating what is not. A plan that is not reviewed dies in phase 1.

Exercises

Exercise 1 — Matching defences to attacks

For each of these eight attacks from lessons 02-02 and 02-03, state: the main measure that neutralises it, a second layer independent of the first, the type of control each one is (preventive, detective, corrective or deterrent) and the phase of the chain they act on.

  1. Password spraying against the team's accounts.
  2. SQL injection in the customer search box.
  3. Ransomware that encrypts the infrastructure and deletes the backups.
  4. IBAN change fraud for a supplier, sent to Sara.
  5. Slow data exfiltration using a stolen token.
  6. Stored XSS in the "notes" field of a booking.
  7. SSRF through a clinic's logo URL.
  8. A compromised third-party CI action.

Exercise 2 — Fixing a dangerous log

This is the Nimbus API's current logging code:

@app.post("/api/v1/sesion")
async def log_in(request: Request):
    data = await request.json()
    logger.info("Login attempt: %s", data)              # (1)
    user = authenticate(data["email"], data["password"])
    if user is None:
        logger.warning("Failed login for %s with password %s",
                       data["email"], data["password"])    # (2)
        raise HTTPException(401, "Incorrect credentials")
    token = issue_token(user)
    logger.info("Login OK user=%s token=%s", user.email, token)   # (3)
    return {"token": token}

@app.get("/api/v1/reservas")
def list_items(current_user = Depends(get_current_user)):
    rows = list_bookings(current_user.tenant_id)
    logger.info("Bookings returned: %s", [dict(r) for r in rows])  # (4)
    return rows

Required: (a) identify the problems on each marked line and explain the specific risk of each; (b) rewrite the code with correct logging; (c) state which three alerts you could build on the corrected log and which attack each would detect; (d) explain why the correct log contains fewer personal data than the incorrect one and still allows more to be detected.

Exercise 3 — Defending the budget to management

Marta gives you 6,000 € a year and one day a week of the team's time for security during the first half of the year. A salesperson has offered her a 5,500 € package that includes a next-generation firewall for the Valencia office and an antivirus for the 40 laptops.

Required:

  1. Argue, with evidence from this module's lessons, why that purchase is not the best allocation of Nimbus's budget.
  2. Propose your alternative allocation of the 6,000 € and of the weekly day, with concrete line items.
  3. Identify the three zero-cost measures that should be done in the first two weeks, and justify the order.
  4. Explain which risk you consciously accept by not spending on the perimeter, and how you would communicate it to Marta in writing.
  5. Define three indicators you would present at six months to demonstrate that the investment has paid off.

Solutions

Solution 1

# Attack Main measure Second layer Types Phase
1 Password spraying Phishing-resistant MFA (preventive) Alert on failures from one origin against several accounts (detective) Prev. + Det. Delivery / Exploitation
2 SQL injection Parameterised queries (preventive) nimbus_api role with no DELETE and no DDL + RLS (preventive, limits the damage); alert on SQL syntax errors (detective) Prev. + Prev./Det. Exploitation
3 Ransomware Immutable backups in a separate account (corrective) Segmentation and MFA that make lateral movement harder (preventive); EDR (detective) Corr. + Prev./Det. Actions
4 IBAN fraud Verification through an alternative channel on the number held on file (preventive) Dual approval by amount (preventive) + a record of the verification (detective/evidential) Prev. + Prev. Delivery
5 Exfiltration with a stolen token Token expiry and minimal scope (preventive) Alert on anomalous export volume (detective) + rate limiting per token (preventive) Prev. + Det. Actions
6 Stored XSS Output encoding (preventive) Content-Security-Policy with report-uri (preventive + detective) and HttpOnly cookies Prev. + Prev./Det. Exploitation
7 SSRF URL validation blocking internal ranges and without redirects (preventive) Egress proxy with an allowlist (preventive) + alert on outbound requests to internal ranges (detective) Prev. + Prev./Det. Exploitation
8 Compromised CI action Pinning actions by commit hash (preventive) CI without access to production secrets and with minimal permissions (preventive); alert on an outbound connection to a new domain from the runner (detective) Prev. + Prev./Det. Delivery

The pattern that emerges: in all eight cases, the second layer is of a different nature from the first — if the first is in code, the second is configuration or detection. That is defence in depth properly understood: layers that do not fail for the same reason. Two layers that both depend on Iván remembering something are, in practice, a single layer.

Solution 2

(a) Problems on each line:

Line Problem Specific risk
(1) Logs the full body of the log-in, including the password in the clear Every password belonging to the team and to customers ends up in plain text in the logging system, which gets copied, exported and often sent to a third party
(2) Explicitly logs the failed password A failed password is usually the real password mistyped, or the one from another service. It is a file of reusable credentials
(3) Logs the issued token Anyone with access to the logs can use that token to take over the session, bypassing MFA (pass-the-cookie from the 02-03 exercise)
(4) Logs every booking returned Patient names, dates and services: data revealing health information, in an application log with no access control equivalent to the database's

(b) Corrected code:

@app.post("/api/v1/sesion")
async def log_in(request: Request):
    data = await request.json()
    email = data.get("email", "")
    user = authenticate(email, data.get("password", ""))

    if user is None:
        logger.warning("auth_fail", extra={
            "email_hash": hashlib.sha256(email.lower().encode()).hexdigest()[:16],
            "ip": request.client.host,
            "agent": request.headers.get("user-agent", "")[:120],
        })
        raise HTTPException(401, "Incorrect credentials")   # uniform message

    token, jti = issue_token(user)      # jti = token identifier, not the token
    logger.info("auth_ok", extra={
        "user_id": user.id,
        "tenant_id": user.tenant_id,
        "jti": jti,
        "ip": request.client.host,
        "mfa": user.mfa_verified,
    })
    return {"token": token}


@app.get("/api/v1/reservas")
def list_items(current_user = Depends(get_current_user), page: int = 1):
    rows = list_bookings(current_user.tenant_id, page)
    logger.info("data_access", extra={
        "user_id": current_user.id,
        "tenant_id": current_user.tenant_id,
        "action": "list_bookings",
        "record_count": len(rows),      # the volume, not the content
        "page": page,
    })
    return rows

Three decisions worth commenting on:

  • email_hash instead of the address on failures. It allows attempts against the same account to be correlated without accumulating a list of valid e-mail addresses in the logs. It is minimisation applied to detection.
  • jti instead of the token. The jti is the token's identifier: it serves to correlate the session and to revoke it, but it does not allow anyone to be impersonated. Detailed in 02-05.
  • A uniform error message. "Incorrect credentials" whether the address does not exist or the password is wrong: it avoids the user enumeration of 02-02.

(c) Three alerts you can build:

Alert Conceptual query Attack detected
Spraying auth_fail grouped by ip, counting distinct email_hash > 5 in 10 min Password spraying (02-02)
Exfiltration data_access grouped by user_id, summing record_count > 5,000/hour Mass export with a stolen token
Session with no preceding authentication data_access with a jti that has no corresponding auth_ok in the last 24 h Pass-the-cookie / session theft

(d) Why fewer data allow more to be detected. The incorrect log accumulates content (passwords, tokens, patient names) that is no use for detecting anything: nobody builds an alert on a patient's name. The correct log accumulates structured metadata — who, what, how much, from where — which is exactly what gets queried and aggregated. The consequence is twofold and very elegant: you detect more and you reduce the impact of a leak of the logs themselves, which stop being a valuable target. Logging well is simultaneously a detection improvement and a data protection measure.

Solution 3

1. Why the proposed purchase is not the best allocation. Four arguments, backed by the module:

  • It does not attack Nimbus's real risk. The main surface is the API in the cloud and identities, not the Valencia office network. An NGFW in the office protects neither the 19 remote employees, nor the cloud account (A-05), nor the API, nor the buckets.
  • A signature-based antivirus does not cover what actually happens. Look back at the myth 2 table in 02-01: it does not stop credential phishing, nor the IDOR, nor the misconfigured bucket, nor the consultancy's credential without MFA, nor CEO fraud.
  • It consumes 92 % of the budget, leaving measures 1 to 8 of the table in section 7 unfunded — the ones with very high impact and low or zero cost.
  • Nimbus has known, unresolved problems today — open SSH, Redis without authentication, a permanent token, untested backups, zero detection — that neither piece of the package fixes. Spending on what is missing before closing what is open is the mistake from the common mistakes section.

2. Alternative allocation:

Line item Amount Justification
Managed EDR for 40 machines 2,400 € The only measure in the table with a real cost; it covers the endpoint and provides detection and the ability to isolate
Simulation and micro-learning platform 700 € Attacks the dominant vector (02-03); measures the report rate
Immutable backup storage in a separate account 600 € It is measure #2 in the table; the cost is storage
Secrets and password manager for the team 500 € Solves the permanent token and password reuse
Managed centralised logging (basic tier) 900 € Enables the Detect function, the weakest according to the CSF
Contingency reserve 900 € A finding from the first scan usually requires unplanned spending
Total 6,000 €

The weekly day is allocated as follows: the whole of phase 1 in the first four weeks (all zero cost), then alternating implementation (logging, alerts, CI) with routine (reviewing alerts, patching, the quarterly review of what is left over).

3. The three zero-cost measures for the first two weeks, in order:

  1. Close the exposed surface (SSH 0.0.0.0/0, Redis without authentication, http.server, node_exporter, snmpd). It goes first because it is exploitable right now by a bot without anybody deciding to attack Nimbus: it is active risk, not potential risk.
  2. MFA on all administrative accounts, including the consultancy's. It goes second because it neutralises spraying, stuffing and most credential phishing in one stroke, and that is the dominant vector.
  3. Rotate the permanent token and put an expiry on every token. It goes third because it closes link 2 of the chained attack in 02-02, and because a leaked token makes MFA irrelevant.

4. The risk accepted and how to communicate it. By not investing in the office perimeter, a residual risk on the Valencia local network is accepted: a compromised device in the office would have more freedom of movement than is desirable. It is partly mitigated at no cost with segmentation on the existing router (guests isolated, data zone closed) and with EDR on the laptops.

The communication to Marta must be written, explicit and dated:

"Accepted risk (date, review in 6 months): the Valencia office perimeter will not be reinforced this half-year. Reason: 100 % of customer data is in the cloud and half the headcount works outside the office, so the physical perimeter is not the main vector. Mitigation applied: segmentation with the current equipment, EDR on every laptop and disk encryption. To be reviewed if the architecture changes or if the office headcount grows. Approved by: Marta Solves."

This is not bureaucracy: it is the difference between accepting a risk (a conscious, documented, reviewable decision) and ignoring it (which is what gets discovered after an incident). The formalisation of this process is studied in 04-01.

5. Three indicators at six months:

Indicator Starting value 6-month target What it demonstrates
Administrative accounts without MFA ~8 0 The dominant vector closed
Verified recovery time (full timed restore) Unknown Known and < 4 h Real ability to survive ransomware
Phishing report rate and time to first alert 11 % / 47 min > 35 % / < 15 min That the human layer is working as detection

A fourth, very visual indicator for management: the number of services exposed to the Internet, which should fall from six to one in the first month. It is the one that communicates progress best to somebody non-technical.


Conclusion

You have the catalogue of the response. You have learned first the method for choosing: which specific attack each measure neutralises, which phase of the chain it acts on, what type of control it is — preventive, detective, corrective or deterrent — and whether it will survive a bad day in a 38-person company. In perimeter and network you have seen the types of firewall and the precision that avoids the most expensive mistake: a WAF buys time and gives visibility, but it does not fix code and does not see an IDOR; you have understood segmentation as the most cost-effective measure against lateral movement, the dual nature of anti-DDoS defence — volumetric, which is bought in, and application-layer, which is programmed — and the evolution of remote access from the all-or-nothing VPN towards just-in-time access with an expiry. In endpoint you have distinguished antivirus from EDR by what really separates them — behaviour, telemetry and the ability to isolate — and you have put patching in its place: the least glamorous measure and one of those that would have prevented the most serious incidents.

In data protection you take away three ideas that hold everything else up: that encryption at rest does not protect against valid credentials and that the key is the real asset; that the 3-2-1 rule extended with immutability and a restore test is the only defence that gives the business back when everything has failed, because modern ransomware seeks out and deletes the backups; and that minimisation is the measure with the best cost/benefit ratio, because what does not exist does not leak. In application and development life cycle you have worked through code review with its four questions, secrets management with its rule of rotating first and investigating afterwards, HTTP headers with a CSP built from default-src 'none', rate limiting as the universal profit-remover, and a real CI workflow whose seven decisions — minimal permissions, actions pinned by hash, full history, an analysis that blocks, filtering by severity, SBOM and preserving the reports — turn a decorative report into an effective control.

In logging and observability you have learned what to log, with its five essential fields, and above all what must never be logged; and you have confirmed in the exercise the most counter-intuitive conclusion of the lesson: the correct log contains fewer personal data than the incorrect one and allows far more to be detected, because detection is built on structured metadata, not on content. And you have finished with the most useful thing for an SME: the twelve highest-return measures — eight of them with zero or low financial cost, none of them a perimeter product — and a 30, 90 and 180-day plan with an owner and a verification for every task, sustained by four quarterly routines in the calendar.

Of those twelve measures, number one was MFA, and several of the rest revolve around the same thing: who you are and what you can do. That is no coincidence. When the perimeter blurs — cloud, remote working, third parties, mobiles — identity becomes the new perimeter. In the next lesson, Identity, Authentication and Access Control (02-05), we will study it in depth: the life cycle of an identity and orphaned accounts, what the current guidance says about passwords, the forms of MFA ordered by phishing resistance, SSO and the identity protocols with the exact difference between OAuth 2.0 and OpenID Connect, sessions and JWTs with their correct validation as against the naive one, the DAC, MAC, RBAC, ABAC and ReBAC authorisation models with Nimbus's concrete design, and privileged accounts, just-in-time access and recertification.

Fundamentals of Information Security Course

Module 1: Introduction to Information Security

Module 2: Cybersecurity

Module 3: Cryptography

Module 4: Risk Management and Protection Measures

Module 5: Security Tools and Techniques

Module 6: Best Practices and Regulations

Module 7: Final Project

© Copyright 2026. All rights reserved