Bitware Labs Est. 2022

Bitware Labs / Anteckningar

Att bygga är enkelt. Att säkra är något helt annat


Ge vem som helst trettio minuter i en modern AI-redigerare och de har byggt en komplett webbapplikation. Mörkt läge, snygga animeringar, databasanslutning, Stripe-betalning och en polerad instrumentpanel. Koden kompilerar utan fel. De trycker upp den till GitHub, klickar på deploy och har en publik URL.

Känslan är berusande. Man känner sig som en fullstack-arkitekt som byggt ett helt mjukvarubolag före lunch.

Men att bygga en app var aldrig det svåra. Att göra den säker nog att överleva på det öppna internet är något helt annat.

Språkmodeller bygger för att koden ska fungera längs den raka, lyckliga vägen – den där användaren fyller i formuläret precis som tänkt och klickar på rätt knapp i Chrome. En AI optimerar för att minimera friktion för stunden. Den bygger inte med fientlighet som grundantagande. Och koden som genereras är som regel inte ens i närheten av säker nog att exponeras direkt mot internet. Den är en öppen inbjudan till den första maskin som råkar titta åt dess håll.

Katalogen över vibecodade haverier

Det handlar inte om subtila kryptografiska angrepp eller avancerade noll-dagars-sårbarheter. Det handlar om samma handfull grova misstag som upprepas i applikation efter applikation, eftersom modellen helt saknar förståelse för nätverk, skalskydd och operativsystem.

Här är vad som rullar ut i produktion varje vecka:

  • .env-filen i webbroten. AI:n sätter upp en minimal nginx- eller Node-konfiguration för att serva den statiska klientkoden. Ingen specificerade en regel för dolda filer. Ett anrop med curl https://app.example.com/.env returnerar DATABASE_URL, JWT_SECRET, AWS_SECRET_ACCESS_KEY och STRIPE_SECRET_KEY i ren klartext. Ingen brandvägg, ingen logg, ingen varning.
  • Hemligheter i klientens Javascript-paket. Utvecklaren ber modellen att snabbt integrera OpenAI eller Stripe från en React-komponent. Modellen löser problemet genom att döpa om variabeln till NEXT_PUBLIC_API_KEY eller baka in nyckeln rakt in i Vite-bygget. Vad vibecodern ser är att gränssnittet fungerar; vad världen ser är att deras produktionsnycklar ligger exponerade i ett offentligt distribuerat JavaScript-skript.
  • Databasen exponerad mot 0.0.0.0. En docker-compose.yml med portmappningen 5432:5432 eller en MongoDB på standardport. Eftersom Docker på Linux manipulerar iptables direkt förbigås UFW helt och hållet i tysthet. Databasen lyssnar öppet mot hela världen, ofta med standardanvändare och ett tomt eller trivialt lösenord.
  • Row Level Security avstängt av bekvämlighet. Under utvecklingen med Supabase eller Firebase möter utvecklaren ett 403-fel. De klistrar in felet i chatten och frågar hur det ska lösas. AI:n föreslår glatt ALTER TABLE users DISABLE ROW LEVEL SECURITY; eller skapar en policy som tillåter allt för alla. Problemet är "löst", utvecklingen kan fortsätta – och hela användardatabasen kan nu läsas av vem som helst med curl.
  • Objektreferenser utan behörighetskontroll (IDOR). Slutpunkten /api/orders/[id] hämtar ordern med angivet ID. Modellen lade till en sökning i databasen, men glömde kontrollera att ordern faktiskt tillhör den inloggade användaren. Utvecklaren testade med sitt eget order-ID och såg att det fungerade. Att byta ut siffran i webbläsarens adressfält laddar ner varenda kunds privata orderhistorik.
  • Oskyddade AI-proxies. En backend-rutt som tar emot användartext och skickar den direkt vidare till en extern språkmodell, utan användarautentisering, IP-begränsning eller budgettak. Inom en timme har en automatiserad bot hittat rutten och förvandlat utvecklarens kreditkort till en gratis beräkningsresurs för externa skript.

En språkmodell bygger det du ber om. Ber du om en funktion får du den kortaste vägen till att funktionen kompilerar. Skyddsräckena, brandväggarna och behörighetsgränserna ingår aldrig i standardprompter.

Från dagar till minuter: Angriparen med ett LLM-lager

För tio eller tjugo år sedan krävde ett intrång ett tålmodigt hantverk.

När jag själv granskade eller penetrerade ett system handlade det om timmar eller dagar av metodiskt arbete. Man körde nmap, samlade in tusentals rader med nätverksdata, körde ffuf eller dirbuster mot kända ordlistor och satt sedan manuellt och läste igenom minifierad JavaScript i webbläsarens felsökare. Man letade efter dolda parametrar, försökte förstå hur utvecklaren tänkt, testade IDOR-variabler en efter en och korrelerade en felkod från en stacktrace med en sårbar version av ett ORM.

Det var ett manuellt, mentalt krävande detektivarbete. Tidsåtgången var i sig ett slags skydd för många mindre system.

I dag är den tiden förbi. Arbetsflödet är detsamma. Verktygen är i grunden desamma: portskannrar, webbfuzzers, HTTP-klienter, headless Chromium.

Men ovanpå verktygen ligger nu ett exekverande språkmodellslager.

Vad som tidigare tog mig timmar eller dagar sker nu på ett par minuter, helt automatiserat och i rasande fart:

nmap / masscan  →  Realtidsanalys av öppna portar och banners
ffuf / katana   →  LLM kartlägger API-rutter ur 5 MB minifierad JS
HTTP 500 trace  →  Modellen genererar omedelbart skräddarsydd exploit
Exploatering    →  Databasdump och exfiltrering på under 180 sekunder

Den kognitiva flaskhalsen hos angriparen är borta. Modellen behöver inte sova, den tröttnar inte på att läsa tiotusentals rader fulkod, och den identifierar arkitektoniska glapp i samma ögonblick som HTTP-svaret landar.

Ser den ett 500-internt fel som läcker ut en felkod från Prisma, vet den exakt vilket databasfält som triggade felet och matar in en payload anpassad för just den ORM-versionen. Ser den ett Vite-paket i källkoden, dammsuger den filen efter dolda API-strängar och parameternamn på tre sekunder.

Säkerhetens brutala asymmetri

Här når vi den hårda verkligheten som vibecoders sällan inser förrän det är för sent:

Som försvarare måste du få precis varje enskild detalj rätt. Angriparen behöver bara att du missar en enda.

För att din applikation ska vara säker på det öppna nätet måste du bemästra och konfigurera hela kedjan:

  • Nätverket: strikt bindning till loopback eller privata WireGuard-adresser, aldrig databaser mot 0.0.0.0, och full kontroll över Dockers iptables-regler.
  • Webbservern: blockering av dolda filer (.env, .git), restriktiva säkerhetsheaders, korrekt CORS och stängda debug-gränssnitt.
  • Autentisering och auktorisering: kryptografiskt säkra sessionskakor, skydd mot CSRF, strikta rollkontroller och obligatorisk ägarkontroll på varje databasfråga.
  • Databasen: principen om minsta behörighet, användarkonton som inte kan köra DDL-satser, och rigoröst aktiverade RLS-regler.
  • Hemlighetshantering: isolerade miljövariabler som aldrig når byggsteg för frontend-klienter.

Om din AI-genererade applikation sköter niohundranittionio av dessa saker galant, men missar en enda rad i nginx-konfigurationen som tillåter hämtning av .env, eller glömmer en ägarkontroll på en raderingsrutt – då är det kört. Systemet faller inte efter en veckas analys; det faller på några minuter.

Och internet väntar inte på att din produkt ska bli känd. Automatiserade skannrar övervakar certifikatloggar och nya DNS-registreringar dygnet runt. Inom tio minuter från att en ny subdomän dyker upp har maskinerna redan sonderat den efter standardläckor.

Varför AI inte kan lösa detta åt dig

Många invänder: "Kan jag inte bara be AI:n att göra koden säker?"

Nej. Inte på det sättet du hoppas.

En språkmodell vet inte hur din server ser ut under huven. Den vet inte om din Linux-kärna körs med AppArmor, om Docker har öppnat hål i din brandvägg, eller om din omvända proxy klipper viktiga autentiseringshuvuden. Modellen kan generera kod som ser säker ut, men säkerhet är inte en textsträng – säkerhet är systemets sammanlagda beteende under fientlig manipulation.

Språkmodeller tränas på offentlig kod, och den överväldigande majoriteten av offentlig kod består av snabbstartsguider, tutorials och demonstrationsprojekt där autentisering och skalskydd medvetet skalats bort för att göra exemplet lättläst. När du ber modellen om kod får du det statistiska genomsnittet av dessa tutorials: naiv, öppen och sårbar kod.

Du kan inte granska säkerheten i ett system om du inte själv förstår hur intrång går till. Och du kan inte instruera en modell att täppa till sårbarheter du inte ens vet kan uppstå.

Hantverket som återstår

Att skriva syntax och bygga ett användargränssnitt har blivit trivialt. Det är ett fantastiskt framsteg för snabba prototyper, interna hjälpmedel och lokala experiment.

Men att bygga är inte detsamma som att driftsätta.

I samma ögonblick som en tjänst exponeras mot det öppna nätet slutar det att vara en lek och blir en försvarsövning mot automatiserade angripare. De verktyg som söker efter dina misstag körs med en analyshastighet som ingen människa kan matcha, drivna av samma språkmodeller som du använde för att generera koden.

Det tar inte timmar längre. Det tar minuter.

Om du inte vet exakt vad som exponeras mot nätet, varför din databas svarar och hur varje förfrågan auktoriseras på maskinnivå – då har du inte byggt en applikation. Du har byggt en måltavla.

Kontakt

Skriv till labbet

Uppdrag, samarbeten eller bara ett hej. Den du skriver till är den som utför arbetet, och jag svarar inom två arbetsdagar.