| name | security-review |
| description | Bruk før commit, push eller pull request for å sjekke at koden er trygg å merge |
| license | MIT |
| metadata | {"domain":"auth","tags":"security pre-commit vulnerability-scanning code-review"} |
Security Review Skill
This skill provides pre-commit and pre-PR security checks for Nav applications. Covers secret scanning, vulnerability scanning, and Nav-specific requirements.
For architecture questions, threat modeling, or compliance decisions, use @security-champion instead.
Automated Scans
Run with run_in_terminal:
trivy repo .
trivy image <image-name> --severity HIGH,CRITICAL
zizmor .github/workflows/
git log -p --all -S 'password' -- '*.kt' '*.ts' | head -100
git log -p --all -S 'secret' -- '*.kt' '*.ts' | head -100
Parameterized SQL (Never Concatenate)
fun findBruker(fnr: String): Bruker? =
jdbcTemplate.queryForObject(
"SELECT * FROM bruker WHERE fnr = ?",
brukerRowMapper,
fnr
)
fun findBrukerUnsafe(fnr: String): Bruker? =
jdbcTemplate.queryForObject(
"SELECT * FROM bruker WHERE fnr = '$fnr'",
brukerRowMapper
)
No PII in Logs
log.info("Behandler sak for bruker", kv("sakId", sak.id), kv("tema", sak.tema))
log.info("Behandler sak for bruker ${bruker.fnr}")
log.info("Navn: ${bruker.navn}")
Secrets from Environment, Never Hardcoded
val dbPassword = System.getenv("DB_PASSWORD")
?: throw IllegalStateException("DB_PASSWORD mangler")
val dbPassword = "supersecret123"
Network Policy (Nais)
Only expose what must be exposed:
spec:
accessPolicy:
inbound:
rules:
- application: frontend-app
outbound:
rules:
- application: pdl-api
namespace: pdl
cluster: prod-gcp
external:
- host: api.external-service.no
OWASP Top 10 Checks
A01: Broken Access Control
@GetMapping("/api/vedtak/{id}")
fun getVedtak(@PathVariable id: UUID): ResponseEntity<VedtakDTO> {
val bruker = hentInnloggetBruker()
val vedtak = vedtakService.findById(id)
if (vedtak.brukerId != bruker.id) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build()
}
return ResponseEntity.ok(vedtak.toDTO())
}
@GetMapping("/api/vedtak/{id}")
fun getVedtak(@PathVariable id: UUID) = vedtakService.findById(id)
A03: Injection
jdbcTemplate.query("SELECT * FROM bruker WHERE fnr = ?", mapper, fnr)
jdbcTemplate.query("SELECT * FROM bruker WHERE fnr = '$fnr'", mapper)
A05: Security Misconfiguration
@Bean
fun corsFilter() = CorsFilter(CorsConfiguration().apply {
allowedOrigins = listOf("https://my-app.intern.nav.no")
allowedMethods = listOf("GET", "POST")
allowedHeaders = listOf("Authorization", "Content-Type")
})
allowedOrigins = listOf("*")
A07: Cross-Site Scripting (XSS)
<BodyShort>{bruker.navn}</BodyShort>
<div dangerouslySetInnerHTML={{ __html: userInput }} />
A08: Insecure Deserialization
@PostMapping("/api/vedtak")
fun create(@RequestBody @Valid request: CreateVedtakRequest): ResponseEntity<VedtakDTO>
objectMapper.apply {
activateDefaultTyping(
polymorphicTypeValidator,
ObjectMapper.DefaultTyping.NON_FINAL
)
}
A09: Logging & Monitoring
log.info("Vedtak opprettet", kv("vedtakId", vedtak.id), kv("sakId", sak.id))
log.info("Vedtak for bruker ${bruker.fnr} opprettet")
File Upload Security
fun validateUpload(file: MultipartFile) {
require(file.size <= 10 * 1024 * 1024) { "File too large (max 10 MB)" }
require(file.contentType in ALLOWED_TYPES) { "Invalid file type" }
val bytes = file.bytes.take(8).toByteArray()
require(verifyMagicBytes(bytes, file.contentType!!)) { "File content does not match type" }
}
private val ALLOWED_TYPES = setOf("application/pdf", "image/png", "image/jpeg")
Dependency Management
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:3.4.1")
}
}
Expanded Checklist
Dependency Management
./gradlew dependencyUpdates
./gradlew dependencyCheckAnalyze
npm audit
npm audit fix
Security Checklist
Related
| Resource | Use For |
|---|
@security-champion | Threat modeling, compliance questions, Nav security architecture |
@auth-agent | JWT validation, TokenX, ID-porten, Maskinporten |
@nais-agent | Nais manifest, accessPolicy, secrets setup |
| sikkerhet.nav.no | Nav Golden Path, authoritative security guidance |