Information security is badly explained when it is explained in the abstract. That is why this whole course revolves around one concrete company, with its servers, its customers, its deadlines and its limited budget. In this first lesson you will meet that company, learn what information security actually is and how it differs from terms that are used as synonyms without being any, and settle the vocabulary you will be using across the seven modules ahead. If you confuse threat with vulnerability, or risk with impact, everything else becomes muddled: conversations with suppliers, audit reports and even security bulletins get misread. Here we put that vocabulary in order.

Contents

  1. Nimbus Reservas, S.L.: the company that will accompany us all course long
  2. What information security is (and what it is not)
  3. The CIA triad: confidentiality, integrity and availability
  4. How each property breaks: examples in code
  5. Beyond the triad: authenticity, non-repudiation and traceability
  6. The AAA trio: authentication, authorisation and auditing
  7. Core vocabulary: asset, threat, vulnerability, exploit, risk, impact and control
  8. Security as a continual process and as a trade-off

  1. Nimbus Reservas, S.L.: the company that will accompany us all course long

Nimbus Reservas, S.L. is a Spanish SME of 38 employees with an office in Valencia. It builds and operates a SaaS (software as a service) product for managing bookings and appointments, used by physiotherapy clinics, gyms and training academies all over Spain. Its customers do not buy a program: they log into a website, and their patients or students book a slot from their phones.

What data Nimbus handles:

Data Example Why it is sensitive
End customer identity First name, surname, DNI (the Spanish national ID number) in some cases Makes specific individuals identifiable
Contact details E-mail address, phone number A direct vector for fraud and impersonation
Appointment history "15/03, physiotherapy, knee rehabilitation" In clinics it indirectly reveals health data
Billing Amounts, line items, tax details of the customer business Financial information subject to legal obligations
Payments Card token returned by the external gateway Nimbus does not store the card number, but it does store the reference

That third row is what changes everything. Nimbus does not think of itself as a company that handles "sensitive data" because all it manages is diaries, but the diary of a physiotherapy clinic is, in practice, a list of people with medical complaints. The course will come back to the legal implications of this in the GDPR lesson (06-03); for now, hold on to the idea: apparently innocuous data can be sensitive because of the context it lives in.

How it is put together technically:

flowchart LR
    subgraph Clients
        SPA[Web SPA]
        APP[Mobile app]
    end
    SPA --> API
    APP --> API
    API["REST API\nPython / FastAPI"]
    API --> DB[(PostgreSQL)]
    API --> S3[S3 bucket\nattachments and backups]
    API --> MAIL[Transactional email\nprovider]
    API --> PAY[Payment gateway]
    CI["GitHub Actions\nCI/CD"] -->|deploys containers| API

The people:

  • Marta — CTO. Decides architecture and priorities; she is the one who has to justify the security budget to the board.
  • Iván — backend developer. Writes the API in Python/FastAPI.
  • Lucía — systems administrator and DevOps. Runs the cloud, the containers and the CI/CD.
  • Rubén — customer support. He is the person who touches real end customer data most often during the day.
  • Sara — head of administration and HR. Custodian of payroll, contracts and invoicing.

The physical and human environment: an office in Valencia with a corporate wifi network and a guest one, some 40 laptops, and half the headcount working remotely. There are three third parties Nimbus depends on: a consultancy that provides systems support with remote access, the transactional e-mail provider and the payment gateway.

Every piece of data, every name and every incident in this course is fictitious. Nimbus does not exist; its resemblance to real companies is precisely the point.


  1. What information security is (and what it is not)

Three terms are used as synonyms and are not. The distinction is not pedantry: it determines who is responsible for what inside an organisation.

Term What it protects Scope Example in Nimbus
Information security Information, on any medium The widest: covers paper, conversations, processes, people Sara keeps the signed contracts in a locked filing cabinet
IT security Information and resources within computer systems Systems, networks, software, hardware, digital data Encrypting the disks of the 40 laptops
Cybersecurity Systems against threats coming from cyberspace Focused on the adversary and on connected systems Defending the Nimbus API from automated scanning of the Internet

A simple way to remember it:

flowchart TD
    SI[Information security\nany medium] --> SINF[IT security\nsystems and digital data]
    SINF --> CIBER[Cybersecurity\nthreats from connected networks]

Each circle sits inside the previous one, but they do not fit perfectly: cybersecurity also deals with things that are not information (the availability of a service, for example, or the control of an industrial device).

Working definition for this course:

Information security, as this course uses the term, is the set of technical, organisational and human measures intended to preserve the confidentiality, the integrity and the availability of information and of the systems that process it, against accidental failures or deliberate actions.

Note three words in that definition:

  • "Set": it is not a product you buy. A firewall does not "give you security"; it is one piece.
  • "Human": most incidents start with a person doing something reasonable in a deceptive context.
  • "Accidental failures or deliberate actions": if Lucía deletes the backup bucket by mistake, the damage is identical to an attacker deleting it. Information security covers both cases; cybersecurity focuses mainly on the second.

The full scope of cybersecurity, with its own terminology and its framework, is developed in lesson 02-01. Here we simply keep the distinction.


  1. The CIA triad: confidentiality, integrity and availability

The CIA triad (Confidentiality, Integrity, Availability) is the mental model everything else rests on. When you are unsure whether something is "a security problem", ask yourself: does it break any of the three?

3.1 Confidentiality

Definition: information is accessible only to those authorised to access it.

Confidentiality is not the same as secrecy. The opening hours of a clinic that is a Nimbus customer are public and lose nothing by being so. Confidentiality means that every piece of data has a defined circle of access and that circle is respected.

Concrete counter-examples in Nimbus (confidentiality failures):

  • An endpoint /api/v1/reservas/{id} that returns the requested booking without checking that it belongs to the customer asking for it. A user of Levante Gym can read the appointments of Turia Clinic by changing the number in the URL.
  • Rubén, in support, exports the complete list of end customers to a CSV "just to test something" and leaves it in his Downloads folder, on an unencrypted laptop.
  • The S3 attachments bucket configured with public read access because that made serving profile pictures easier.
  • The API logs print the full body of requests, including phone numbers and appointment notes, and those logs are visible to the whole external consultancy.

3.2 Integrity

Definition: information is accurate and complete, and is modified only in an authorised and controlled way.

Integrity has two faces worth separating:

  • Integrity of the data: the data has not been altered (not by an attacker, not by a software bug, not by a disk failure).
  • Integrity of the origin: the data comes from whoever it claims to come from (this overlaps with authenticity, which we cover in section 5).

Concrete counter-examples in Nimbus (integrity failures):

  • A maintenance script runs an UPDATE with no WHERE and sets the same status on all 240,000 bookings in the database.
  • The amount on an invoice is recalculated in the browser and the API trusts what the client sends it, instead of recalculating it on the server.
  • Two simultaneous requests book the same time slot because there is no concurrency control: the diary ends up inconsistent.
  • An attacker modifies an audit record to erase the trace of what they did.

3.3 Availability

Definition: information and services are accessible when those authorised to use them need them.

It is the property most often forgotten when people talk about "security", and the one the customer notices fastest. If Turia Clinic opens at 08:00 and the Nimbus API is not responding, by 08:05 Rubén's phone is ringing.

Concrete counter-examples in Nimbus (availability failures):

  • Ransomware encrypts the servers and the backups reachable from the same network.
  • The domain's TLS certificate expires on a Sunday and the mobile app stops connecting.
  • A deployment breaks a database migration and it has to be reverted by hand over three hours.
  • The transactional e-mail provider suffers an outage and appointment reminders do not go out: technically the API works, but the service the customer bought does not.

3.4 The three together, and their tensions

Property Question it answers It breaks when... Typical control
Confidentiality Who can see it? Somebody unauthorised reads it Encryption, access control, minimisation
Integrity Is it correct and unchanged? Someone or something alters it improperly Validation, hashes/signatures, transactions, write permissions
Availability Is it there when needed? The service or the data cannot be used Backups, redundancy, capacity, recovery plan

The three compete with each other. If Marta decides to encrypt the database with a key only she knows, she gains confidentiality and loses availability (if Marta is off sick, nobody can restore). If Lucía grants read permissions to the whole team so that nobody gets blocked, she gains availability and loses confidentiality. A good part of security work consists of deliberately choosing the balance point, not of maximising one property.


  1. How each property breaks: examples in code

Seeing the flaw in code fixes it far better than the definition does. The three examples below are written against Iván's API and the Nimbus database.

4.1 Breaking confidentiality: the query that returns too much

# api/bookings.py  --  VULNERABLE VERSION
from fastapi import APIRouter

router = APIRouter()

@router.get("/api/v1/reservas/{booking_id}")
async def get_booking(booking_id: int, db=Depends(get_db)):
    row = await db.fetch_one(
        "SELECT * FROM bookings WHERE id = :id",
        {"id": booking_id},
    )
    return row

What it does, line by line:

  1. Declares an endpoint that receives a booking_id from the URL.
  2. Queries the bookings table filtering only by that identifier.
  3. Returns the whole row as it is.

Why it breaks confidentiality: there are two independent flaws.

  • It does not check ownership of the resource. The query does not filter by the authenticated user's business (tenant). Anyone holding a valid session can request /api/v1/reservas/91544 and read the appointment of another customer's patient. This pattern has a name of its own: IDOR (insecure direct object reference), and we will meet it among the attacks in module 2.
  • SELECT * returns extra columns. Even if the user were entitled to see the booking, the row includes internal fields (internal_notes, payment_gateway_id, created_by_user_id) that should never leave the database.

Corrected version:

# api/bookings.py  --  CORRECTED VERSION
@router.get("/api/v1/reservas/{booking_id}")
async def get_booking(booking_id: int, current_user=Depends(get_current_user), db=Depends(get_db)):
    row = await db.fetch_one(
        """
        SELECT id, date_time, service, status, end_customer_name
        FROM bookings
        WHERE id = :id
          AND tenant_id = :tenant     -- the resource must belong to the user's business
        """,
        {"id": booking_id, "tenant": current_user.tenant_id},
    )
    if row is None:
        raise HTTPException(status_code=404, detail="Not found")
    return row

Two changes and both matter: the AND tenant_id = :tenant ties the resource to the authenticated user, and the explicit column list stops internal fields leaking out. On top of that, a 404 is returned rather than a 403: that way the attacker does not learn whether the identifier exists.

4.2 Breaking integrity: the uncontrolled UPDATE

-- Run by mistake in production during a night maintenance window
UPDATE bookings
SET status = 'cancelled';

What happens: with no WHERE clause, PostgreSQL updates every row in the table. All 240,000 bookings belonging to every Nimbus customer move to status "cancelled". Nobody broke into the system; there was no attack. Integrity broke all the same.

How an operation like that is protected:

-- 1. Always wrap it in a transaction and check before committing
BEGIN;

UPDATE bookings
SET status = 'cancelled'
WHERE tenant_id = 42
  AND date_time::date = DATE '2026-08-14'   -- the day the clinic closes
  AND status = 'confirmed';

-- 2. Verify the number of affected rows BEFORE committing
--    If the number does not match expectations, undo everything:
-- ROLLBACK;

COMMIT;

Explanation of each defence:

  • BEGIN / COMMIT create a transaction: until it is committed, nothing is final. If the row count is surprising, a ROLLBACK leaves everything as it was.
  • The WHERE narrows the scope by three criteria instead of one. The more specific it is, the less damage a mistake can do.
  • The condition status = 'confirmed' makes the operation idempotent and bounded: it does not touch bookings that were already cancelled.

To this you add structural defences we will see in 01-03: the account the API uses to connect to the database should not have permission to run a mass UPDATE, and maintenance work should run under a different account and be reviewed by a second person.

4.3 Breaking availability: the query that takes the service down

# Reporting endpoint  --  DANGEROUS VERSION
@router.get("/api/v1/informes/historico")
async def historical_report(db=Depends(get_db)):
    # No date limit, no pagination, no timeout
    return await db.fetch_all("SELECT * FROM bookings ORDER BY date_time")

Why it breaks availability: every call loads the entire table into memory and sorts it. All it takes is Rubén hitting "Refresh" five times in a row for the API process to consume all the container's memory, for the orchestrator to restart it and for every customer to see errors. No attacker is required: the fragility is already there, and all an attacker does is discover it and repeat it.

Defended version:

@router.get("/api/v1/informes/historico")
async def historical_report(
    date_from: date, date_to: date, page: int = 1,
    current_user=Depends(get_current_user), db=Depends(get_db),
):
    if (date_to - date_from).days > 366:
        raise HTTPException(400, "The maximum range is 366 days")

    return await db.fetch_all(
        """
        SELECT id, date_time, service, status
        FROM bookings
        WHERE tenant_id = :tenant AND date_time BETWEEN :date_from AND :date_to
        ORDER BY date_time
        LIMIT 500 OFFSET :offset
        """,
        {"tenant": current_user.tenant_id, "date_from": date_from, "date_to": date_to,
         "offset": (page - 1) * 500},
    )

Three availability defences in a handful of lines: a range limit (nobody asks for ten years at once), pagination with LIMIT (the cost of each request is bounded) and a tenant filter (which incidentally protects confidentiality again). A single fix can reinforce several properties at once; that is the norm.


  1. Beyond the triad: authenticity, non-repudiation and traceability

The CIA triad covers a lot, but not everything. Three additional properties turn up constantly in regulations and contracts.

5.1 Authenticity

Definition: the assurance that an entity (a person, a system, a message) really is who or what it claims to be.

It is different from confidentiality. An e-mail can arrive encrypted — confidential — and come from a forged sender — not authentic. In Nimbus: when an e-mail arrives saying "It's Marta, please change the bank account for payroll", the question that fails is not who can read this? but did Marta really write it?.

5.2 Non-repudiation

Definition: the impossibility for whoever performed an action to later deny having performed it.

It is a legal property before it is a technical one. If a Nimbus customer claims they never cancelled 200 appointments, Nimbus needs to be able to prove that the request came from their session, from their IP address, at that time and with their token. Technically it rests on digital signatures (module 3) and on audit records whose integrity is preserved.

5.3 Traceability

Definition: the ability to reconstruct what happened, who did it, when and against which resource.

Without traceability there is no possible investigation of an incident. It is the difference between being able to tell a customer "these 14 records were accessed on Tuesday at 03:12 from this account" and having to tell them "we don't know". In front of a regulator, the second answer is far worse than the first.

Property Question Rests on Example in Nimbus
Authenticity Are you who you say you are? Credentials, signatures, certificates Verifying the signature of the payment gateway webhook
Non-repudiation Can you deny you did it? Digital signature + tamper-evident log Signed record of the mass cancellations
Traceability What exactly happened? Logs with actor, action, resource and time Log of Rubén's accesses to customer records

An example of a Nimbus log line that underpins traceability:

2026-07-30T03:12:44Z level=INFO event=data_access actor_id=u-1042 actor=ruben@nimbusreservas.example
  tenant=42 action=read resource=end_customer:88231 fields=[name,phone,history]
  ip=203.0.113.55 user_agent="NimbusSupport/2.1" request_id=7f3a91cc trace_id=b21e...

Note what it contains and what it does not contain: there is who, what, when, on what and from where, but there are no values of the data that was read. An audit log that copies the sensitive data becomes a confidentiality problem in its own right.


  1. The AAA trio: authentication, authorisation and auditing

AAA is the operational model that implements much of the above. The first two get confused constantly, so let us take it slowly.

Question Moment In the Nimbus API
Authentication Who are you? At log-in / on every request Validating the JWT token in the Authorization header
Authorisation What are you allowed to do? On every action Checking that the role allows cancelling bookings for that tenant
Auditing / Accounting What did you do? Afterwards, and continually Recording the event in the access log

Seen as the flow of a real Nimbus request:

sequenceDiagram
    participant R as Ruben (support)
    participant API as Nimbus API
    participant DB as PostgreSQL
    participant LOG as Audit log
    R->>API: DELETE /api/v1/reservas/91544 (token)
    API->>API: 1. AUTHENTICATION: token valid and not expired?
    API->>API: 2. AUTHORISATION: support role + booking of tenant 42?
    API->>DB: UPDATE bookings SET status='cancelled' WHERE id=91544 AND tenant_id=42
    API->>LOG: 3. AUDITING: actor, action, resource, time, IP
    API-->>R: 204 No Content

And in code, explicitly separating the three responsibilities:

@router.delete("/api/v1/reservas/{booking_id}", status_code=204)
async def cancel_booking(
    booking_id: int,
    request: Request,
    current_user=Depends(get_current_user),   # (1) AUTHENTICATION
    db=Depends(get_db),
):
    # (2) AUTHORISATION: two distinct checks, both of them necessary
    if "bookings:cancel" not in current_user.permissions:
        raise HTTPException(403, "Insufficient permission")

    affected = await db.execute(
        "UPDATE bookings SET status='cancelled' WHERE id=:id AND tenant_id=:t AND status='confirmed'",
        {"id": booking_id, "t": current_user.tenant_id},   # ...and the resource must be theirs
    )
    if affected == 0:
        raise HTTPException(404, "Not found")

    # (3) AUDITING
    logger.info(
        "event=booking_cancelled actor_id=%s tenant=%s resource=booking:%s ip=%s",
        current_user.id, current_user.tenant_id, booking_id, request.client.host,
    )

The three classic mistakes this code avoids:

  1. Confusing authenticating with authorising. "They are logged in" does not mean "they may do it". The permission check is a separate line from the token validation.
  2. Authorising by role only and forgetting the resource. Rubén does hold the bookings:cancel permission — but only over the bookings of the tenants assigned to him. Role and ownership.
  3. Logging only the errors. The audit log must also record successful actions on sensitive data; those are precisely the ones you need to be able to reconstruct afterwards.

The concrete techniques for authenticating well — MFA, SSO, session management, RBAC and ABAC models — are developed in lesson 02-05. Here you only need the three concepts and their order to be clear.


  1. Core vocabulary: asset, threat, vulnerability, exploit, risk, impact and control

This is the section you will reread most often. These seven terms are misused daily, even in professional reports.

Term Definition Nature Example in Nimbus
Asset Something of value to the organisation and therefore worth protecting What you have The PostgreSQL database holding the bookings
Threat A potential event or actor capable of causing harm to an asset What exists out there; you do not control it A ransomware group scanning the Internet for exposed databases
Vulnerability A weakness in an asset or a control that a threat can take advantage of What fails on your side; you do control it PostgreSQL port 5432 reachable from the Internet with a weak password
Exploit The concrete means (code, technique or procedure) that takes advantage of a vulnerability The tool that turns the threat into reality A script that tries default credentials against that port
Risk The combination of the likelihood that a threat exploits a vulnerability and the resulting impact An estimate, not a fact "High likelihood of unauthorised access to the DB, with critical impact"
Impact The real consequence for the business if the risk materialises The damage, measurable 2 days of downtime, notification to the AEPD, loss of 6 customers
Control The measure (technical, organisational or physical) that reduces the risk What you do about it Close the port, require VPN, rotate credentials, alert on attempts

The template sentence that chains them together. Memorise this structure; it works for writing up any security finding professionally:

A threat [ransomware groups scanning the Internet] could take advantage of a vulnerability [port 5432 exposed with weak credentials] by means of an exploit [a credential brute-force script] against an asset [the bookings database], with an impact [data encryption, service outage and mandatory notification to the supervisory authority]. The resulting risk is assessed as high, and it is mitigated with the control [restricting access to the private network and requiring certificate-based authentication].

Practise by rewriting findings with that template. A report that says "we have a threat of an open port" is misusing the words: an open port is a vulnerability, not a threat.

The three most frequent confusions:

  • Threat vs. vulnerability. The threat is outside and you do not eliminate it (you cannot make ransomware groups stop existing). The vulnerability is inside and you can indeed close it. Your work is exercised on vulnerabilities and controls, not on threats.
  • Risk vs. impact. Impact is "how much it hurts if it happens". Risk additionally incorporates "how likely it is to happen". A catastrophic impact with negligible likelihood may be a smaller risk than a moderate impact that happens every week.
  • Vulnerability vs. exploit. The vulnerability is the hole; the exploit is the lockpick. There are vulnerabilities with no known exploit (less urgent) and vulnerabilities with a public, automated exploit (far more urgent).

The detailed catalogue of threats and vulnerability types, with their CVE and CVSS identifiers, is the content of the next lesson (01-02). How to calculate and prioritise risk with matrices arrives in 04-01.


  1. Security as a continual process and as a trade-off

8.1 It is not a state, it is a cycle

Marta could commission an audit, fix every finding and declare "Nimbus is secure". It would not last long:

  • New vulnerabilities are published every week in the dependencies Iván uses.
  • Every CI/CD deployment changes the system, and with it the attack surface.
  • Every person joining or leaving the company changes the map of accesses.
  • Attackers change technique when the previous one stops working.

That is why security is modelled as a continual cycle, not as a project with an end date:

flowchart LR
    ID[Identify\nassets and risks] --> PR[Protect\ncontrols]
    PR --> DE[Detect\nmonitoring]
    DE --> RE[Respond\nincidents]
    RE --> RC[Recover\ncontinuity]
    RC --> ID

This cycle — identify, protect, detect, respond, recover — is the backbone of the course: modules 4 and 5 develop it in full. Note that protecting is only one fifth of it. An organisation that invests only in protection and cannot detect or respond is betting on never failing, which is not a strategy.

8.2 The trade-off: security, usability and cost

Every security measure is paid for in one of these currencies:

Measure in Nimbus Gains Costs
Encrypting the 40 laptops Confidentiality if one is lost Rollout time, risk of losing recovery keys
Requiring a second factor from Rubén on every access Confidentiality, authenticity Seconds per session; possible pushback from the team
Hourly backups in another region Availability, integrity Storage and transfer cost
Manual review of every deployment Integrity Delivery speed; team frustration
Blocking DB access except over VPN Confidentiality Friction for the external consultancy

The right question is never "is this secure?", because the answer is always "not entirely". The right question is:

How much risk are we accepting, who has accepted it in writing, and in exchange for what?

That "who" matters a great deal: accepting a risk is a business decision, not a technical one. Lucía can explain that not encrypting the backups implies such and such a risk, but the one who accepts living with it is the management team. We will come back to this in the security policies lesson (04-02).

And a practical corollary: a security measure people cannot comply with does not protect, it generates workarounds. If Nimbus forces a password change every 30 days with impossible rules, there will eventually be a sticky note under a keyboard. This is the principle of psychological acceptability, which we will meet formally in 01-03.


Common Mistakes and Tips

Common mistakes when starting out in security:

  • Believing "we have nothing interesting". It is the most expensive mistake in an SME. Nimbus holds no state secrets, but it does hold personal data on thousands of people, a cloud infrastructure an attacker can use to mine cryptocurrency, and a trusted relationship with customers that serves as a bridge towards them. Most attacks are opportunistic and automated: they do not choose the victim, they find it.
  • Reducing security to confidentiality. Many teams think only about "stopping data theft" and neglect integrity and availability, which are the ones that halt the business most immediately.
  • Using "threat" for everything. "We have several threats in the scan report" — no: you have vulnerabilities. Using the vocabulary precisely improves decisions, because each term points to a different kind of action.
  • Confusing authenticated with authorised. It is the origin of an enormous share of data leaks in multi-tenant APIs like the Nimbus one.
  • Treating security as a final phase. "Once we finish the product, we'll do the security review". Fixing a design flaw afterwards costs orders of magnitude more than avoiding it.
  • Trusting that the cloud provider "takes care of it". The provider secures the infrastructure; the configuration, the permissions and the data are Nimbus's responsibility. This is the shared responsibility model, detailed in 05-07.

Tips:

  • Faced with any technical decision, ask yourself: does this affect C, I or A? It is a surprisingly effective filter.
  • Write your findings with the template sentence from section 7. It will force you to know whether you are describing a threat, a vulnerability or a risk.
  • When you propose a control, always state its cost and its friction. A security proposal with no declared cost is not rejected, it is ignored.
  • Start from what you know you have. Nothing in this course works without an inventory (01-04).

Exercises

Exercise 1 — Classifying incidents against the CIA triad

For each Nimbus situation, state which property or properties of the CIA triad are affected and justify it briefly:

  1. Lucía discovers that the S3 bucket holding appointment attachments (scanned medical reports) has allowed anonymous read access for the last 4 months.
  2. A deployment introduces a bug that causes the status field of bookings to always be saved as pending, even when the user confirms it.
  3. The transactional e-mail provider suffers a 6-hour outage and appointment reminders do not go out.
  4. A former employee still has an active account and logs into the admin panel two weeks after leaving, exports the customer list and deletes their own entry from the log.

Exercise 2 — Rewriting a finding with the right vocabulary

The following paragraph, written by an intern, mixes the terms up. Identify the incorrect uses and rewrite it using the template sentence from section 7.

"We have detected a serious risk: the test server has a threat because it uses the password admin1234. The impact is that there is an exploit. We recommend a vulnerability control."

Exercise 3 — Separating authentication, authorisation and auditing

Read this Nimbus API endpoint and identify which AAA elements are present, which are missing and which security property is compromised by each absence.

@router.get("/api/v1/clientes-finales/exportar")
async def export_customers(current_user=Depends(get_current_user), db=Depends(get_db)):
    rows = await db.fetch_all("SELECT * FROM end_customers")
    return {"total": len(rows), "data": rows}

Solutions

Solution 1

  1. Confidentiality, seriously so: documents containing health data accessible without authorisation. Additionally: if the bucket also allowed writes, there would be an integrity problem too; that is worth checking. The fact that it has been the case for 4 months aggravates the impact, because there is no way to establish who accessed it (a traceability failure).
  2. Integrity: the stored data does not reflect reality. There is no improper access and no service outage, but the information is wrong. Secondarily it affects the functional availability of the service (clinics cannot operate with a diary that never confirms anything), although the root cause is one of integrity.
  3. Availability: the contracted service (notifying patients) is not available, even though the API responds. It is a good example of availability being measured from the customer's point of view, not the server's, and of it depending on third parties too.
  4. All three, plus the extended properties: confidentiality (exports data without authorisation), integrity (alters the log by deleting their trace), availability not directly, but traceability and non-repudiation destroyed by tampering with the audit trail. It is also a process failure: the employee's departure did not trigger the revocation of accesses.

Solution 2

Incorrect uses:

  • "has a threat because it uses the password admin1234" → a weak password is a vulnerability, not a threat.
  • "The impact is that there is an exploit" → an exploit is not an impact; impact is the consequence for the business.
  • "vulnerability control" → a control is a concrete measure; it has to be named.
  • "We have detected a serious risk" applied to an observed fact: what was observed is the vulnerability; the risk is the estimate derived from it.

Correct rewrite:

We have identified a vulnerability on the test server: the administrative account uses the default password admin1234. The corresponding threat is the automated processes that sweep the Internet trying known credentials, which have public and trivial exploits for this case. The affected asset is the test server, which additionally holds a partial copy of real booking data. The estimated impact includes unauthorised access to personal data, use of the server as a jump point into the internal network and possible mandatory notification to the supervisory authority. We assess the risk as high because of how easy exploitation is. Proposed controls: rotate the credential to a unique generated password, restrict administrative access to the private network and remove the real data from the test environment.

Solution 3

  • Authentication: present. The get_current_user dependency validates who is making the request.
  • Authorisation: absent twice over. There is no check that (a) the user holds a specific export permission, nor (b) that the data returned belongs to their tenant. The query SELECT * FROM end_customers with no WHERE returns the end customers of every business that is a Nimbus customer. Any authenticated user, including a gym receptionist, obtains the complete database. Property compromised: confidentiality, on a massive scale.
  • Auditing: absent. A full export of personal data is exactly the kind of action that must be recorded. Without it, traceability and non-repudiation are lost: if that data shows up published tomorrow, Nimbus will have no way of knowing who took it out.
  • Extra — availability: loading the entire table into memory and serialising it to JSON, with no pagination and no limits, makes the endpoint vulnerable to resource exhaustion, just as in section 4.3.

Version corrected in the essentials:

@router.get("/api/v1/clientes-finales/exportar")
async def export_customers(request: Request, current_user=Depends(get_current_user), db=Depends(get_db)):
    if "customers:export" not in current_user.permissions:   # authorisation by permission
        raise HTTPException(403, "Insufficient permission")

    rows = await db.fetch_all(
        "SELECT id, name, email FROM end_customers WHERE tenant_id = :t LIMIT 5000",
        {"t": current_user.tenant_id},                        # authorisation by resource
    )
    logger.info("event=customer_export actor_id=%s tenant=%s rows=%s ip=%s",
                current_user.id, current_user.tenant_id, len(rows), request.client.host)  # auditing
    return {"total": len(rows), "data": rows}

Conclusion

In this lesson you have met Nimbus Reservas — the Valencian SME whose booking SaaS will serve as our laboratory throughout the course — and you have settled the vocabulary that makes the rest possible. You have seen that information security, IT security and cybersecurity are concentric circles and not synonyms; that the CIA triad (confidentiality, integrity, availability) is the filter through which to evaluate any technical decision, and how each of its properties breaks with real code: a query with no tenant filter, an UPDATE with no WHERE, an endpoint with no pagination. You have added authenticity, non-repudiation and traceability to the triad, and you have put the AAA trio in order — authenticate, authorise, audit — by explicitly separating the three responsibilities in a FastAPI endpoint.

Above all, you have separated seven words that get confused daily: asset, threat, vulnerability, exploit, risk, impact and control, and you have a template sentence that chains them together so you can write up any finding precisely. And you have accepted the uncomfortable premise of the trade: security is not a state you reach, but a cycle you maintain, and it is always paid for in usability or in money.

With the vocabulary now in place, it is time to fill it with content. In the next lesson, Types of Threats and Vulnerabilities (01-02), we will look at the real catalogue: what threats exist according to their origin and their target, what malware families there are and how to tell them apart, what types of vulnerability we will find in the Nimbus environment, and how to read the identifiers the whole industry uses — CWE, CVE and CVSS — to name and prioritise the holes that need closing.

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