OWASP släppte sin uppdaterade Top 10:2025 i slutet av 2025, och listan skiljer sig rejält från utgåvan de flesta säkerhetsteam fortfarande bygger sina rutiner kring. Två kategorier är helt nya, en har hoppat från femte till andra plats, och SSRF har flyttats in under ett bredare paraply. Om din härdningscheck fortfarande är byggd på 2021 års ordning har du sannolikt ett gap just nu. Den här guiden går igenom exakt vad som ändrats och hur du uppdaterar din applikation, ditt API-lager och din CI/CD-pipeline i 12 konkreta steg, med fungerande kod du kan klistra in direkt.

Guiden är skriven för utvecklare och säkerhetsansvariga på svenska och nordiska bolag som redan har en applikation i produktion och behöver ett praktiskt migreringsspår, inte bara en teoretisk genomgång. Räkna med att avsätta cirka 90 minuter för att gå igenom samtliga steg och köra verktygen mot en testmiljö.

Passar den här guiden er roll? Om ni är en enskild utvecklare eller ett litet team utan dedikerad säkerhetsfunktion är stegen skrivna så att de går att genomföra utan extern konsult. Är ni ett större team med en befintlig säkerhetsavdelning fungerar guiden istället som ett diff-underlag att stämma av mot er nuvarande baseline, så att ingen av de nya kategorierna hamnar mellan stolarna under omorganisationen från 2021 till 2025 års struktur.

Vad är nytt i OWASP Top 10:2025 jämfört med 2021

Den största förändringen är att A02:2025 Security Misconfiguration har klättrat från femte till andra plats. Det speglar en verklighet där felkonfigurerade API-gateways, öppna CORS-policyer och kvarglömda debug-headers orsakar fler faktiska incidenter än klassisk injection just nu, enligt Qualys genomgång av den nya listan. Den andra stora nyheten är A03:2025 Software Supply Chain Failures, en helt ny kategori som breddar det gamla “Vulnerable and Outdated Components” till att även täcka byggkedjan, CI/CD-tillägg och tredjeparts-API:er du konsumerar (inte bara paket du installerar).

Samtidigt har Cryptographic Failures, Injection och Insecure Design alla tappat en placering var, trots att de fortfarande är kritiska. Den sista nyheten är A10:2025 Mishandling of Exceptional Conditions, som ersätter den gamla fristående SSRF-kategorin. SSRF försvinner inte, den har istället flyttats in under A01 Broken Access Control eftersom OWASP nu klassar den som ett åtkomstkontrollsproblem snarare än ett eget fenomen.

2025-kategoriPlacering 2025Placering 2021Förändring
A01 Broken Access Control11Oförändrad, inkluderar nu SSRF-mönster
A02 Security Misconfiguration25Upp 3 platser
A03 Software Supply Chain Failures3Ny kategori (utökar gamla A06)
A04 Cryptographic Failures42Ner 2 platser
A05 Injection53Ner 2 platser
A06 Insecure Design64Ner 2 platser
A07 Authentication Failures77Oförändrad, namnet förfinat
A08 Software or Data Integrity Failures88Oförändrad
A09 Security Logging & Alerting Failures99Oförändrad, namnet förfinat
A10 Mishandling of Exceptional Conditions10Ny kategori (ersätter fristående SSRF)

Det här är också relevant utanför webbappar. OWASP publicerade i mars 2026 en separat Top 10 för agentiska applikationer, vilket visar att samma mönster (bruten åtkomstkontroll, felkonfiguration, osäker konsumtion av tredjepartstjänster) nu appliceras på AI-agenter också. Om ni bygger något med LLM-API:er i produktionsflödet är A03 och A02 extra relevanta, eftersom obegränsad resursförbrukning mot dyra modell-API:er kan bli en ekonomisk överbelastningsattack, inte bara en säkerhetsincident.

Värt att notera är också att OWASP API Security Top 10, den separata listan specifikt för API-lagret, fortfarande utgår från 2023 års utgåva och inte har uppdaterats i takt med webbapplistan. Det innebär att BOLA fortsatt toppar API-listan som API1, medan samma sårbarhetsmönster i webbapplistan nu ligger under det bredare A01 Broken Access Control. Ni behöver med andra ord förhålla er till båda listorna parallellt om er applikation både har ett traditionellt webbgränssnitt och ett publikt API, vilket gäller de flesta SaaS-produkter som byggs i Norden idag.

Varför det här är akut för nordiska bolag just nu

Det är lätt att avfärda en listuppdatering som administrativt pyssel, men siffrorna säger något annat. Enligt Noname Securitys studie, återgiven i Nordic APIs genomgång av 2026 års API-landskap, har 91 procent av organisationer haft minst en API-säkerhetsincident under de senaste tolv månaderna. Det är inte längre en fråga om er organisation drabbas, utan hur snabbt ni upptäcker det när det händer, och det är precis det A09 Logging & Alerting Failures handlar om.

Nordic APIs pekar dessutom på en rad namngivna incidenter de senaste åren där just de mönster som nu flyttat upp i rankingen låg till grund för intrånget: 23andMe, Optus, Trello, Volkswagen, WhatsApp, Avelo Airlines och Authy har alla haft API-relaterade säkerhetshändelser som gått att koppla direkt till bruten åtkomstkontroll eller felkonfigurerade endpoints. Ingen av dessa var nya, exotiska attacktekniker, det var samma grundläggande brister som A01 och A02 nu prioriterar högst.

OrganisationHuvudsaklig bristkategoriMotsvarande OWASP 2025-kategori
23andMeBristfällig åtkomstbegränsning mot användardataA01 Broken Access Control
OptusOautentiserad, exponerad API-endpointA02 Security Misconfiguration
TrelloPublikt sökbar profildata via öppet APIA02 Security Misconfiguration
VolkswagenFelkonfigurerad molnlagring kopplad till API-lagerA02 Security Misconfiguration
WhatsAppObjektnivå-läckage via kontaktuppslagningA01 Broken Access Control

För svenska och nordiska bolag som redan rapporterar incidenter under NIS2 är kopplingen direkt: ju fler av dessa kategorier ni har täckt innan något händer, desto kortare blir både utredningstiden och den rapporteringsplikt som annars triggas. Att lägga 90 minuter på den här guiden är, ärligt talat, billigare än en enda incidentutredning.

Det finns också ett rent affärsmässigt argument. Ju fler kunder ni har inom finans, offentlig sektor eller andra reglerade branscher, desto oftare kommer säkerhetsfrågor upp redan i upphandlingsfasen. Att kunna svara konkret på vilken version av OWASP-listan er applikation är härdad mot, och när den senast verifierades, är numera en vanlig fråga i svenska leverantörsbedömningar, inte bara en teknisk detalj som stannar hos utvecklingsteamet.

Förutsättningar: verktyg och kompetens du behöver

Du behöver inte byta hela verktygslådan för att migrera till 2025-listan, men följande bör finnas på plats innan du börjar. Vi utgår från ett Node.js-baserat exempel i den här guiden, men principerna gäller oavsett språk.

  • Node.js 22 LTS (kodnamn “Jod”) eller senare, med npm 10
  • Docker Engine, senaste stabila versionen, för att köra scanningsverktyg isolerat
  • Semgrep CLI, senaste versionen, för statisk kodanalys mot OWASP-regler
  • OWASP ZAP, senaste stabila versionen, för dynamisk skanning (DAST) mot en test-URL
  • Trivy, senaste versionen, för sårbarhetsskanning av beroenden och containeravbildningar
  • Sigstore cosign för signering av byggartefakter i steget om supply chain-skydd
  • Grundläggande kunskap i Git, CI/CD (vi använder GitHub Actions som exempel) och HTTP
  • Adminåtkomst till er API-gateway eller reverse proxy (nginx, Envoy eller motsvarande)

Ingen av dessa verktyg kräver licenskostnad för att komma igång, samtliga har öppen källkod-varianter som räcker gott för ett team i den här storleksordningen. Investeringen ligger i tid, inte i budget, vilket gör den här migreringen genomförbar även för mindre bolag utan en dedikerad säkerhetsavdelning.

Har ni redan en generell OWASP Top 10-implementation på plats sedan tidigare (till exempel enligt 2021-listan) kan ni behandla den här guiden som ett diff-spår: hoppa direkt till de tre steg som täcker A02, A03 och A10, eftersom det är där det faktiska arbetet ligger.

Räkna med att en person med backend-erfarenhet klarar hela migreringen på 1–2 arbetsdagar för en medelstor applikation med ett tiotal endpoints, förutsatt att verktygen redan är installerade och att ni inte behöver bygga en helt ny CI/CD-pipeline från grunden. Har ni fler mikrotjänster tar det längre tid per tjänst, men samma checklista och samma kodmönster återanvänds rakt av.

Om er applikation är byggd i ett annat språk än Node.js, exempelvis Python, Java eller .NET, byt bara ut kodexemplen mot motsvarande bibliotek i er stack (till exempel Argon2-bindningar för Python, eller inbyggda skyddsmekanismer i Spring Security för Java). Strukturen på de tolv stegen och ordningen ni bör göra dem i förblir densamma oavsett språk, det är kategorierna i OWASP-listan som styr arbetet, inte tekniken.

Steg 1–2: Kartlägg attackytan och bygg ett hotmodelleringsschema

Innan du rör kod behöver du en lista över allt som faktiskt är exponerat. Nordic APIs pekar i sin genomgång av 2026 års incidenter ut “zombie-endpoints”, alltså gamla beta-API:er som glömts kvar exponerade i molnmiljön, som en återkommande orsak till intrång. Steg ett är därför en fullständig inventering.

  1. Lista alla externa och interna endpoints, inklusive de som saknar dokumentation i OpenAPI-specen.
  2. Markera varje endpoint med dataklassificering (publik, intern, känslig, GDPR-reglerad).
  3. Identifiera vilka endpoints som konsumerar tredjeparts-API:er eller LLM-tjänster, dessa hör till A03-riskytan.

Bygg därefter ett enkelt hotmodelleringsschema per endpoint: vem kan anropa den, vilken data returneras, och vad händer om autentiseringen kringgås. Du behöver inte ett tungt verktyg för detta, ett kalkylblad med kolumnerna endpoint, ägare, dataklass, autentiseringskrav och senaste granskningsdatum räcker långt för att ge full täckning inför resten av guiden.

Steg 3: Stäng A01 – Broken Access Control (nu inklusive SSRF)

A01 är fortfarande etta, och den vanligaste konkreta bristen är fortsatt Broken Object Level Authorization (BOLA), där en autentiserad användare kan komma åt ett annat objekt genom att bara ändra ett ID i URL:en. Eftersom SSRF nu klassas under A01 måste du även validera alla utgående anrop som applikationen själv gör baserat på användarinput, inte bara inkommande anrop.

// middleware/authorizeResource.js
function authorizeResource(getOwnerId) {
  return async function (req, res, next) {
    try {
      const resourceOwnerId = await getOwnerId(req.params.id);
      if (!resourceOwnerId) {
        return res.status(404).json({ error: 'not_found' });
      }
      if (resourceOwnerId !== req.user.id && !req.user.roles.includes('admin')) {
        return res.status(403).json({ error: 'forbidden' });
      }
      next();
    } catch (err) {
      next(err);
    }
  };
}

// route.js
router.get(
  '/invoices/:id',
  requireAuth,
  authorizeResource(async (id) => invoiceRepo.getOwnerId(id)),
  invoiceController.get
);

module.exports = { authorizeResource };

Nyckeln är att auktoriseringskontrollen sker per objekt, på serversidan, varje gång, aldrig genom att lita på ett fält i klientens JWT om vilket objekt användaren “borde” få se. Om er applikation gör utgående HTTP-anrop baserat på användarangivna URL:er (bildhämtning, webhooks, importfunktioner) lägger ni till en allowlist för tillåtna domäner i samma lager, det stänger SSRF-vektorn utan separat kod.

Testa kontrollen genom att logga in som en vanlig användare och manuellt öka eller minska ID:t i URL:en mot en resurs som tillhör någon annan. Får du fortfarande tillbaka data är det ett kritiskt fynd, oavsett hur väl resten av applikationen är skyddad. Gör det här till ett automatiserat testfall i er testsvit, inte bara en manuell kontroll som körs en gång vid release, eftersom regressionsrisken är hög varje gång någon lägger till en ny endpoint.

Steg 4: Härda A02 – Security Misconfiguration

Att A02 klättrat till andra plats handlar sällan om exotiska buggar. Det handlar om standardinställningar som aldrig ändrades: CORS med wildcard-origin, verbose felmeddelanden som läcker stacktraces, saknade säkerhetsheaders och admin-paneler som är nåbara utan extra nätverksbarriär. Detta är dessutom det billigaste steget att åtgärda, eftersom det oftast är konfiguration snarare än ny kod.

// server.js
const helmet = require('helmet');
const cors = require('cors');

app.disable('x-powered-by');

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      objectSrc: ["'none'"],
      frameAncestors: ["'none'"],
    },
  },
  hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
}));

app.use(cors({
  origin: ['https://app.exempel.se'],
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));

// Generiska felsvar i produktion, inga stacktraces till klienten
app.use((err, req, res, next) => {
  console.error(err); // logga internt, aldrig till svaret
  res.status(err.status || 500).json({ error: 'internal_error' });
});

Komplettera med en engångsgenomgång av molnkonsolen: publika lagringskonton, standardlösenord på interna admin-verktyg och öppna portar i säkerhetsgrupper är samma kategori av fel, bara utanför applikationskoden. Kör en snabb Trivy-skanning mot era container-images för att fånga felkonfigurationer i basimagen innan de hamnar i produktion.

Ett vanligt misstag är att härda produktionsmiljön men lämna staging öppen med samma dataset som produktion, fast utan samma skyddslager. Om staging pekar mot en kopia av kunddata bör den skyddas exakt lika hårt som produktionen, annars har ni bara flyttat er svagaste punkt, inte tagit bort den. Gå igenom alla miljöer, inte bara den som kunderna faktiskt använder.

Steg 5: Skydda mot A03 – Software Supply Chain Failures

Det här är den nya kategori som kräver mest faktiskt nytt arbete. Den täcker tre saker: sårbara beroenden (det gamla A06:2021), en komprometterad byggkedja (CI/CD-tillägg, self-hosted runners), och osäker konsumtion av tredjeparts- och LLM-API:er utan schemavalidering. Har ni redan en SBOM-process på plats sedan tidigare kan ni återanvända den här, men lägg till signering av byggartefakter om det saknas.

# .github/workflows/supply-chain.yml
name: supply-chain-check
on: [push, pull_request]

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - run: npm ci
      - run: npm audit --audit-level=high
      - name: Skanna beroenden med Trivy
        run: |
          trivy fs --exit-code 1 --severity HIGH,CRITICAL .
      - name: Signera byggartefakt med cosign
        run: |
          cosign sign-blob --yes dist/app.tar.gz \
            --output-signature dist/app.tar.gz.sig

Om er applikation anropar externa AI-API:er, validera alltid svarsschemat innan det används vidare i affärslogiken, och sätt hårda kvoter per anropande tjänst. En trasig eller manipulerad tredjepartsrespons ska aldrig kunna fortplanta sig utan kontroll genom er egen pipeline.

Glöm inte era CI/CD-tillägg själva. Self-hosted runners, tredjeparts GitHub Actions från okända underhållare, och byggagenter med för breda behörigheter är alla en del av samma riskyta som paketberoenden. Lås varje action till en specifik commit-hash istället för en flyttbar tagg, och begränsa vilka secrets en given workflow faktiskt får läsa. Ett komprometterat CI/CD-steg kan skriva om er kod innan den ens når produktionsmiljön, vilket gör det till en av de svåraste attackerna att upptäcka i efterhand.

Steg 6: Fixa A04 – Cryptographic Failures

Kryptografiska brister har tappat en placering men är fortfarande vanliga: data i klartext i loggar, egenhändigt hopsnickrad kryptering, och lösenordshashning utan salt eller med för lågt kostnadstal. Standardrekommendationen 2026 är TLS 1.3 för allt i transit och Argon2id för lösenordshashning i vila.

const argon2 = require('argon2');

async function hashPassword(plain) {
  return argon2.hash(plain, {
    type: argon2.argon2id,
    memoryCost: 19456, // ~19 MB
    timeCost: 2,
    parallelism: 1,
  });
}

async function verifyPassword(hash, plain) {
  return argon2.verify(hash, plain);
}

module.exports = { hashPassword, verifyPassword };

Kontrollera samtidigt att TLS-terminatorn (lastbalanserare eller reverse proxy) inte tillåter fallback till TLS 1.2 för känsliga endpoints, och att interntrafik mellan mikrotjänster inte går okrypterad bara för att den stannar innanför ert eget nätverk.

Ett annat vanligt fel är att blanda ihop kryptering med kodning. Base64 är ingen säkerhetsåtgärd, det är bara ett annat sätt att skriva samma data. Sök igenom kodbasen efter platser där Buffer.from(...).toString('base64') eller motsvarande används på känslig data i tron att det ger skydd, och byt ut det mot faktisk kryptering med ett bibliotek som testats i produktion, aldrig en egenskriven algoritm.

Steg 7: Blockera A05 – Injection

Injection har tappat till femte plats men slår fortfarande hårt när den träffar, särskilt i äldre kodbaser med handskriven SQL. Regeln är oförändrad sedan tidigare listor: parameteriserade queries alltid, aldrig strängkonkatenering med användarinput.

// FEL: sårbar för SQL-injection
const bad = `SELECT * FROM users WHERE email = '${input}'`;

// RÄTT: parameteriserad query
const { rows } = await pool.query(
  'SELECT id, email, role FROM users WHERE email = $1',
  [input]
);

Samma princip gäller NoSQL-frågor, kommandoradsanrop och mallmotorer. Kör Semgrep mot repot med OWASP-regeluppsättningen som en del av CI, det fångar de flesta injection-mönster innan kod ens når review.

Injection har tappat i ranking, men det beror mer på att andra kategorier vuxit snabbare än att problemet försvunnit. ORM-bibliotek har gjort rå SQL mindre vanligt i nyskriven kod, men äldre integrationslager, rapportgeneratorer och interna admin-verktyg innehåller ofta handskrivna queries som aldrig granskats sedan de skrevs. Prioritera en genomgång av just de äldre delarna av kodbasen, inte bara det som byggs nu.

Steg 8–9: Täck A06 Insecure Design och A07 Authentication Failures

Insecure Design handlar inte om en enskild bugg utan om att säkerhet aldrig fanns med i kravställningen. Praktiskt innebär det en snabb designgranskning innan ny funktionalitet byggs: finns det en gräns för hur många lösenordsförsök som tillåts, kan ett flöde missbrukas för att läcka data i bulk, är rate limiting satt per användare eller bara per IP.

För A07 Authentication Failures är minimikravet 2026 flerfaktorsautentisering för alla konton med förhöjd behörighet, kort livslängd på access-tokens (15–30 minuter) med roterande refresh-tokens, och att sessionscookies alltid sätts med HttpOnly, Secure och SameSite=Strict. Passkeys (WebAuthn) är att föredra över SMS-baserad tvåfaktor där ni har möjlighet, eftersom SMS är sårbart för SIM-swapping.

Designgranskningen bör dessutom ställa frågan “vad händer om den här funktionen missbrukas exakt som den är byggd, inte om den hackas”. Ett exportflöde som är tänkt att hämta en kunds egna fakturor kan, utan extra kontroll, användas för att hämta tusentals fakturor i en loop om ID:na är sekventiella och rate limiting saknas. Det är inte en bugg i klassisk mening, det är en design som aldrig testades mot sitt eget missbrukspotential.

Steg 10–11: Täck A08 Integrity Failures och A09 Logging & Alerting Failures

A08 handlar om att lita på data eller kod vars ursprung inte kan verifieras, till exempel att auto-uppdatera ett bibliotek utan att kontrollera signaturen, eller att deserialisera objekt från en okontrollerad källa. Lös detta genom att alltid verifiera checksummor och signaturer på allt som laddas ner i produktionsmiljön, inte bara i byggsteget.

Ett konkret exempel är auto-uppdaterare i klientapplikationer eller CMS-plugins. Om uppdateringsmekanismen hämtar en ny version över HTTP utan att verifiera en digital signatur kan en angripare som lyckas manipulera nätverkstrafiken (till exempel via en komprometterad DNS-post) leverera skadlig kod som ser ut som en legitim uppdatering. Kräv alltid signaturverifiering innan en uppdatering appliceras automatiskt, oavsett hur pålitlig källan verkar vara.

A09 har fått ordet “Alerting” tillagt i namnet av en anledning: loggning utan larm är i praktiken osynlig tills det är för sent. Strukturerad loggning som faktiskt triggar en varning vid avvikande mönster är skillnaden mellan att upptäcka ett intrång på minuter eller på veckor.

Skilj också på loggning för felsökning och loggning för säkerhet. Applikationsloggar som skriver ut varje request i debug-nivå hjälper er inte att hitta en pågående attack, de bara döljer den i volym. Bygg en separat, smalare ström för säkerhetshändelser (misslyckade inloggningar, 403-svar, ovanliga geografiska mönster) och koppla den till ett larmsystem som faktiskt väcker någon, inte bara en logg som lagras och glöms.

const logger = require('pino')();

function logSecurityEvent(type, req, meta = {}) {
  logger.warn({
    event: type,
    ip: req.ip,
    userId: req.user?.id ?? 'anonymous',
    path: req.originalUrl,
    ...meta,
  }, `security_event:${type}`);
}

// Exempel: upprepade misslyckade inloggningar
if (failedAttempts >= 5) {
  logSecurityEvent('brute_force_suspected', req, { failedAttempts });
  // skicka vidare till larmsystem (t.ex. webhook till Slack/SIEM)
}

Steg 12: Stoppa A10 – Mishandling of Exceptional Conditions och automatisera i CI/CD

A10 är den andra helt nya kategorin och handlar om felhantering: logiska fel som gör att systemet “failar öppet” istället för stängt, ohanterade undantag som avslöjar interna detaljer, eller affärslogik som antar att ett fel aldrig inträffar. Ett typexempel är en betalningsfunktion som, vid timeout mot en extern leverantör, antar att betalningen gick igenom istället för att anta motsatsen.

// FEL: failar öppet vid timeout
try {
  await paymentGateway.charge(order);
  order.status = 'paid';
} catch (err) {
  order.status = 'paid'; // antar att det gick bra – farligt
}

// RÄTT: failar stängt, kräver explicit bekräftelse
try {
  const result = await paymentGateway.charge(order);
  order.status = result.confirmed ? 'paid' : 'pending_review';
} catch (err) {
  order.status = 'failed';
  logSecurityEvent('payment_exception', req, { orderId: order.id });
}

Slutsteget är att knyta ihop alla föregående kontroller i en enda pipeline som körs på varje pull request, så att ingen av dessa checkar är beroende av att någon kommer ihåg att köra dem manuellt: Semgrep för statisk analys, Trivy för beroenden, ZAP baseline-skanning mot en staging-URL, och npm audit för kända CVE:er. Målet är att en utvecklare aldrig ska behöva minnas att köra ett säkerhetsverktyg manuellt, pipelinen ska göra det åt dem varje gång, och den ska blockera mergen om ett kritiskt fynd dyker upp, inte bara skicka en rapport ingen läser.

Rekommenderad prioriteringsordning om ni har begränsad tid

Få team hinner göra allt på en gång. Om ni måste välja vad som görs först, prioritera efter en kombination av hur högt kategorin rankas 2025 och hur snabbt den faktiskt går att åtgärda, inte bara efter placeringen i listan.

  1. A02 Security Misconfiguration först. Det är nästan aldrig ny kod, bara konfiguration, och går ofta att åtgärda på en eftermiddag med stor effekt.
  2. A01 Broken Access Control näst. Kräver mer arbete eftersom det rör affärslogik, men är den kategori som orsakar flest faktiska dataläckor enligt de incidenter vi listat ovan.
  3. A03 Software Supply Chain Failures tredje. Sätt upp automatiserad skanning i CI direkt, även om ni inte hinner åtgärda alla fynd samma vecka, synligheten i sig minskar risken.
  4. A07 Authentication Failures och A09 Logging & Alerting Failures parallellt, eftersom bättre loggning gör att ni snabbare upptäcker om något av de tidigare stegen missades.
  5. Resterande kategorier (A04, A05, A06, A08, A10) enligt er egen risknivå, de är alla viktiga men statistiskt mindre akuta just nu enligt 2025 års rankning.

Komplett fungerande projekt: en härdad Node.js-mikrotjänst

Nedan är ett minimalt men komplett exempel som samlar de viktigaste kontrollerna från guiden i en enda körbar tjänst. Spara filen som app.js, installera express, helmet, cors, argon2 och pino via npm, och starta med node app.js. Exemplet täcker A01 (auktorisering per objekt), A02 (säkerhetsheaders och generiska felsvar), A04 (Argon2id-hashning) och A10 (fail-closed-mönster i felhanteraren) i en och samma fil, så att ni ser hur kontrollerna samverkar istället för att bara läsa dem isolerat.

const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const argon2 = require('argon2');
const crypto = require('crypto');
const logger = require('pino')();

const app = express();
app.disable('x-powered-by');
app.use(express.json());
app.use(helmet({ hsts: { maxAge: 31536000 } }));
app.use(cors({ origin: ['https://app.exempel.se'], credentials: true }));

const users = new Map(); // demo-lagring, byt mot riktig databas

app.post('/register', async (req, res, next) => {
  try {
    const { email, password } = req.body;
    const hash = await argon2.hash(password, { type: argon2.argon2id });
    users.set(email, { id: crypto.randomUUID(), email, hash });
    res.status(201).json({ status: 'created' });
  } catch (err) { next(err); }
});

app.get('/invoices/:id', requireAuth, authorizeResource(getInvoiceOwner), (req, res) => {
  res.json({ id: req.params.id, status: 'ok' });
});

// Central felhanterare: aldrig stacktrace till klienten (A02), fail closed (A10)
app.use((err, req, res, next) => {
  logger.error({ err }, 'unhandled_error');
  res.status(500).json({ error: 'internal_error' });
});

app.listen(3000, () => logger.info('Härdad tjänst igång på port 3000'));

Kör en snabb verifiering med curl efter start:

$ curl -i -X POST http://localhost:3000/register \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"ByT-Detta-Losenord!2026"}'

HTTP/1.1 201 Created
content-type: application/json
{"status":"created"}

Får du 403 forbidden när du testar /invoices/:id med ett ID som inte tillhör din testanvändare fungerar auktoriseringskontrollen som avsett, det är själva poängen med steg 3. Bygger ni vidare på exemplet i en riktig kodbas, byt ut Map-lagringen mot en riktig databas, lägg till en migrationsstrategi för lösenordshash om ni någon gång byter hashalgoritm, och koppla in den strukturerade loggningen från steg 10–11 i samma felhanterare som redan finns här.

Vanliga fallgropar när du migrerar till OWASP Top 10:2025

De flesta team som misslyckas med migreringen gör det inte för att de saknar teknisk kompetens, utan för att de behandlar den nya listan som en engångscheckbox istället för en process. Nedan är de fallgropar vi ser oftast när nordiska team går från 2021 till 2025 års kategorier.

  • Att bara byta namn på gamla kontroller. A03 Software Supply Chain Failures är bredare än gamla “Vulnerable Components”, den kräver även kontroll av CI/CD-kedjan och tredjeparts-API-konsumtion, inte bara npm audit.
  • Att glömma att SSRF flyttat. Om er checklista fortfarande har en egen SSRF-rad separat från åtkomstkontroll riskerar ni att missa att den nu ska testas tillsammans med A01, inte isolerat.
  • Att köra ZAP eller Semgrep en gång och kalla det klart. Statisk och dynamisk skanning måste köras på varje pull request, en engångsskanning fångar bara läget just den dagen.
  • Att härda applikationslagret men glömma molnkonsolen. A02 handlar lika mycket om öppna lagringskonton och säkerhetsgrupper som om HTTP-headers.
  • Att sätta rate limiting bara per IP. Delade nätverk (kontor, mobiloperatörens CGNAT) gör IP-baserad begränsning otillräcklig, komplettera med per-konto-gränser.
  • Att signera byggartefakter men aldrig verifiera signaturen vid deploy. Signering utan verifiering i produktionssteget ger falsk trygghet.
  • Att anta att A10 bara gäller try/catch. Mishandling of Exceptional Conditions inkluderar affärslogiska antaganden, inte enbart ohanterade undantag i koden.
  • Att köra hela migreringen som ett enda stort projekt. Team som försöker göra alla tolv steg på en gång tenderar att tappa fart efter första veckan. Bryt ner arbetet per kategori och released kontinuerligt, det ger snabbare faktisk skyddseffekt än ett stort samlat släpp längre fram.

Felsökning: 8 vanliga problem och lösningar

Även med rätt verktyg och rätt kod stöter de flesta team på samma återkommande problem när kontrollerna ska rullas ut i en riktig pipeline. Tabellen nedan samlar de vanligaste symptomen vi sett, tillsammans med den mest sannolika orsaken och en konkret åtgärd, så att ni slipper felsöka från grunden varje gång.

SymptomTrolig orsakLösning
ZAP-skanningen timeoutar mot stagingRate limiting blockerar skannerns egna anropWhitelista skannerns IP tillfälligt i staging, aldrig i produktion
Semgrep flaggar falska positiva i testerTestfiler saknar undantag i regeluppsättningenLägg till .semgrepignore för testkataloger
CORS-fel efter att policyn stramats åtFrontend anropar från en origin som inte finns i allowlistanLägg till exakt origin, undvik wildcard även i test
cosign sign-blob misslyckas i CISaknad eller felaktig nyckelkonfiguration i pipelinenVerifiera att OIDC-identiteten för runnern är korrekt kopplad i Sigstore
Argon2-hashning är för långsam i produktionFör högt memoryCost för instansens RAMSänk memoryCost stegvis och mät svarstid tills den är under 250 ms
Trivy rapporterar sårbarheter utan patchBasimagen är föråldradByt till senaste stabila basimage och bygg om
Larm från A09-loggning drunknar i brusFör låg tröskel för vad som räknas som säkerhetshändelseJustera tröskelvärden och gruppera larm per användare/IP
Betalningsflödet failar öppet trots fixEtt annat kodspår hanterar undantaget innan din nya logik nåsSök igenom hela anropskedjan efter dubbla try/catch-block

Avancerade tips för mogna säkerhetsteam

När grundkontrollerna från de tolv stegen är på plats handlar nästa fas om att göra dem svåra att avinstallera av misstag och lätta att mäta över tid. Följande punkter passar team som redan har en fungerande säkerhetsprocess och vill flytta fram positionerna ytterligare.

  • Kör Semgrep och ZAP som gate i CI, inte bara som rapport, så att en pull request faktiskt blockeras vid kritiska fynd istället för att bara flaggas.
  • Bygg en intern “OWASP 2025-diff”-runbook som del av onboarding för nya utvecklare, så att kunskapen inte sitter hos en enskild person.
  • Sätt separata SLA:er för A02- och A03-fynd jämfört med övriga kategorier, eftersom de nu är högst rankade och bör åtgärdas snabbast.
  • Använd policy-as-code för att koda era A01-auktoriseringsregler så att de kan testas automatiskt, inte bara läsas i kodgranskning.
  • Kör kvartalsvisa red team-övningar specifikt mot A10-scenarier, eftersom felhanteringslogik sällan täcks av vanliga penetrationstester.
  • Mät “tid till upptäckt” och “tid till åtgärd” per OWASP-kategori separat, en samlad siffra döljer ofta att A02 och A03 tar mångdubbelt längre tid att lösa än övriga.
  • Låt säkerhetsteamet äga en kvartalsvis genomgång av vilka endpoints som tillkommit sedan senaste inventeringen, attackytan växer annars snabbare än checklistan hinner uppdateras.

Sammanfattning: från 2021 till 2025 i praktiken

Kärnan i migreringen är inte att lära om från grunden, det mesta av det ni redan gjort för äldre versioner av listan gäller fortfarande. Det som faktiskt kräver nytt arbete är tre saker: en konfigurationsgenomgång för A02, ett verktygslager för supply chain-kontroll för A03, och en genomgång av felhanteringslogiken för A10. Gör ni de tre sakerna, tillsammans med de kontroller ni redan har för åtkomst, autentisering och kryptering, ligger ni väl i linje med 2025 års lista, och sannolikt före de flesta konkurrenter som ännu inte har gjort bytet.

Vanliga frågor om OWASP Top 10:2025

Är OWASP Top 10:2025 officiellt släppt?
Ja, listan finns publicerad på OWASP:s egen sajt och är den aktuella versionen att utgå från 2026.

Måste vi bygga om hela applikationen för att följa den nya listan?
Nej. De flesta kontrollerna för A01, A04, A05, A06, A07 och A08 är i stort sett desamma som i 2021 års lista. Det faktiska merarbetet ligger i A02 (konfigurationsgenomgång), A03 (supply chain-verktyg) och A10 (felhanteringslogik).

Vad hände med SSRF som egen kategori?
Den är inte borttagen, utan flyttad in under A01 Broken Access Control i webbapplistan, eftersom OWASP nu ser den som ett åtkomstkontrollsproblem. I den separata API Security Top 10 finns SSRF fortfarande kvar som en egen risk.

Skiljer sig OWASP Top 10:2025 från OWASP API Security Top 10?
Ja, det är två olika listor. Webbapplistan (den vi går igenom här) täcker applikationer generellt, medan API Security Top 10 är specifik för API-lagret och fortfarande har BOLA som sin högst rankade risk.

Hur ofta uppdaterar OWASP listan?
Historiskt har uppdateringar skett med flera års mellanrum, inte årligen, så 2025-listan förväntas vara den styrande referensen under flera år framöver.

Räcker det med ett verktyg för att täcka hela listan?
Nej. Statisk analys (Semgrep), dynamisk skanning (ZAP) och beroendeskanning (Trivy) täcker olika kategorier och behöver köras tillsammans, inget enskilt verktyg täcker alla tio kategorierna.

Var A03 Software Supply Chain Failures helt oväntad?
Inte om man följt branschen. Den är en direkt utökning av den gamla “Vulnerable and Outdated Components”-kategorin från 2021, med bredare omfattning kring byggkedjan och tredjepartskonsumtion.

Påverkar det här vår rapporteringsplikt enligt NIS2?
Indirekt, ja. Ju fler av de tio kategorierna ni redan har täckt innan en incident inträffar, desto snabbare kan ni fastställa orsak och omfattning, vilket direkt påverkar hur fort ni kan uppfylla rapporteringskraven gentemot tillsynsmyndigheten.

Kan vi använda samma checklista för både interna och externa API:er?
Ja, men prioritera externa API:er först eftersom de har en större exponerad attackyta. Interna API:er bör ändå täckas, särskilt A01 och A03, eftersom en angripare som väl tagit sig in i nätverket annars kan röra sig fritt mellan tjänster.

Behöver vi ett dedikerat säkerhetsteam för att klara det här?
Nej. De flesta stegen i den här guiden är avsedda att genomföras av det ordinarie utvecklingsteamet. Ett dedikerat säkerhetsteam gör processen snabbare och mer träffsäker, men avsaknad av ett sådant är inte en ursäkt för att skjuta upp de grundläggande kontrollerna, särskilt A01 och A02 som ger störst effekt per investerad timme.

Relaterad läsning

Källor och fördjupning: OWASP Top 10:2025, OWASP API Security Project, OWASP Cheat Sheet Series, Nordic APIs om OWASP Top Ten 2025 och Qualys genomgång av förändringarna.