Provides code-level security patterns and fixes aligned with the OWASP Top 10 to protect applications on Nais.
Install
mkdir -p .claude/skills/security-owasp && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16643" && unzip -o skill.zip -d .claude/skills/security-owasp && rm skill.zipInstalls to .claude/skills/security-owasp
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
OWASP Top 10:2025 kodenivå-mønstre for Kotlin, Go, Java og Node.js — tilgangskontroll, forsyningskjede, injeksjon og feilhåndteringKey capabilities
- →Implement resource-level access checks
- →Validate outbound URLs for SSRF prevention
- →Restrict CORS to known origins
- →Pin dependencies to exact versions
- →Use bcrypt for password hashing
- →Parameterize all SQL queries
How it works
The skill provides tactical security patterns and code examples for Kotlin, Go, Java, and Node.js to address OWASP Top 10:2025 vulnerabilities.
Inputs & outputs
When to use security-owasp
- →Implement IDOR protection in Kotlin
- →Validate outbound URLs in Go
- →Secure M2M token validation
- →Prevent code injection patterns
About this skill
OWASP Top 10:2025 — Code-Level Security
Tactical security patterns for Kotlin, Go, Java, and Node.js on NAIS, aligned with the 2025 OWASP Top 10.
Complements @security-champion-agent (architecture-level threat modeling) and the security-review skill (scanning tools).
Full code examples for each category: see
examples.mdin this skill directory.
A01: Broken Access Control (incl. SSRF)
// ❌ IDOR — trusts user-supplied ID without ownership check
get("/api/vedtak/{id}") {
val vedtak = vedtakRepository.findById(call.parameters["id"]!!.toLong())
call.respond(vedtak)
}
// ✅ Verify ownership before returning resource
get("/api/vedtak/{id}") {
val bruker = call.hentBruker()
val vedtak = vedtakRepository.findById(call.parameters["id"]!!.toLong())
?: return@get call.respond(HttpStatusCode.NotFound)
if (vedtak.brukerId != bruker.id) return@get call.respond(HttpStatusCode.Forbidden)
call.respond(vedtak.toDTO())
}
// ✅ SSRF prevention — validate outbound URL against allowlist
func fetchExternal(targetURL string) error {
parsed, err := url.Parse(targetURL)
if err != nil { return err }
if !isAllowedHost(parsed.Host) { return fmt.Errorf("host not allowed: %s", parsed.Host) }
// proceed with request
}
- Deny by default — require explicit grants, not explicit denials
- Resource-level checks — not just "is authenticated" but "owns this resource"
- M2M tokens — validate
azpclaim againstAZURE_APP_PRE_AUTHORIZED_APPS - SSRF — validate outbound URLs; use Nais
accessPolicy.outboundas defense-in-depth
A02: Security Misconfiguration
// ❌ Open CORS
install(CORS) { anyHost() }
// ✅ Restrict to known origins
install(CORS) { allowHost("my-app.intern.nav.no", schemes = listOf("https")) }
// ❌ Debug endpoint exposed on public ingress
mux.HandleFunc("/debug/pprof/", pprof.Index)
// ✅ Debug endpoints on separate internal-only port (Nais handles this)
internalMux := http.NewServeMux()
internalMux.HandleFunc("/debug/pprof/", pprof.Index)
go http.ListenAndServe(":9090", internalMux) // not exposed via ingress
- CORS restricted to known origins — never
*oranyHost() - Debug/admin endpoints not on public ingress
- Error responses sanitized — no stack traces, SQL errors, or file paths to client
- Default-deny Nais
accessPolicy— explicit inbound/outbound only
A03: Software Supply Chain Failures (NEW in 2025)
// go.sum provides integrity verification — always commit it
// Use govulncheck for known vulnerabilities
// $ govulncheck ./...
// ✅ Pin dependencies to exact versions in go.mod
require (
golang.org/x/crypto v0.31.0
github.com/jackc/pgx/v5 v5.7.2
)
// build.gradle.kts — use dependency locking and BOM
dependencyLocking { lockAllConfigurations() }
dependencyManagement {
imports { mavenBom("org.springframework.boot:spring-boot-dependencies:3.4.1") }
}
// Run: ./gradlew dependencies --write-locks
# ✅ GitHub Actions — pin to full SHA, never @main or floating tags
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# ❌ Vulnerable to supply chain attack
- uses: actions/checkout@main
- Pin all dependencies to exact versions; use lockfiles
- Scan dependencies:
govulncheck ./...,trivy repo .,./gradlew dependencyCheckAnalyze - GitHub Actions pinned to full commit SHA (not tags)
- Generate SBOM for production artifacts when possible
- Prefer well-maintained, first-party packages
A04: Cryptographic Failures
// ❌ Disabling TLS verification
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
// ✅ Default TLS config (Go enforces TLS 1.2+ by default)
client := &http.Client{}
// ❌ Weak hashing for passwords
val hash = MessageDigest.getInstance("MD5").digest(password.toByteArray())
// ✅ bcrypt for password hashing
val hashed = BCrypt.hashpw(password, BCrypt.gensalt(12))
- Passwords: bcrypt (cost ≥ 12) or argon2id — never MD5/SHA-1/SHA-256
- Secrets: always from Nais environment variables or Secret resources — never hardcoded
- TLS 1.2+: never set
InsecureSkipVerify: true - Encryption: AES-256-GCM; rotate keys periodically
A05: Injection
// ❌ SQL injection via string template
session.run(queryOf("SELECT * FROM vedtak WHERE status = '$status'").map { ... }.asList)
// ✅ Parameterized query (Kotliquery)
session.run(queryOf("SELECT * FROM vedtak WHERE status = ?", status).map { ... }.asList)
// ❌ Command injection via shell
exec.Command("sh", "-c", fmt.Sprintf("process %s", userInput)).Run()
// ✅ Pass arguments directly (no shell interpretation)
exec.Command("process", userInput).Run()
- All SQL queries parameterized (
?/$1) — never string concatenation - No shell execution with user-controlled input
- Validate/sanitize all external input at service boundary
A09: Security Logging and Alerting Failures
// ✅ Structured logging with correlation ID, no PII
log.info("Vedtak opprettet", kv("vedtakId", vedtak.id), kv("sakId", sak.id))
// ❌ PII in logs — GDPR violation
log.info("Vedtak for bruker ${bruker.fnr}")
- No PII in logs (fnr, name, address, tokens)
- Audit trail for sensitive operations (vedtak, utbetaling, tilgang)
- Correlation IDs propagated across services (OpenTelemetry trace context)
- Alerting on anomalous patterns (auth failures, rate spikes)
A10: Mishandling of Exceptional Conditions (NEW in 2025)
// ❌ Panic leaks to caller, crashes service
func processRequest(data []byte) Result {
var req Request
json.Unmarshal(data, &req) // ignores error, req may be zero-value
return handle(req)
}
// ✅ Handle errors explicitly, fail safely
func processRequest(data []byte) (Result, error) {
var req Request
if err := json.Unmarshal(data, &req); err != nil {
return Result{}, fmt.Errorf("invalid request payload: %w", err)
}
return handle(req)
}
// ❌ Swallowing exceptions silently
fun process(data: String): Result {
try { return parse(data) }
catch (e: Exception) { return Result.empty() } // silent failure, no logging
}
// ✅ Log, wrap, and surface errors appropriately
fun process(data: String): Result {
return try { parse(data) }
catch (e: Exception) {
log.error("Parsing failed", kv("error", e.message))
throw ServiceException("Could not process input", e)
}
}
- Always handle errors — never ignore returned errors in Go
- Recover from panics at HTTP handler boundaries (middleware)
- Fail securely: deny access by default when state is uncertain
- Sanitize error messages: internal details stay in logs, not in responses
- Centralized error handling via middleware/exception mappers
Quick Reference Checklist
- A01 — Resource-level access checks on every endpoint (not just auth)
- A01 — M2M tokens validate
azpagainst pre-authorized apps - A01 — Outbound URLs validated; Nais egress policy configured
- A02 — CORS restricted to known origins
- A02 — Debug endpoints not on public ingress
- A02 — Error responses sanitized (no stack traces to client)
- A03 — Dependencies pinned to exact versions with lockfiles
- A03 —
govulncheck/trivy repo .pass without HIGH/CRITICAL - A03 — GitHub Actions pinned to full SHA
- A04 — bcrypt/argon2id for passwords, never MD5/SHA-1
- A04 — TLS 1.2+ enforced, no
InsecureSkipVerify - A04 — Secrets from environment/Nais, never hardcoded
- A05 — All SQL queries parameterized (
?/$1) - A05 — No shell execution with user input
- A07 — JWT validates
exp,iss,aud, and algorithm - A08 — Deserialization into concrete types only
- A09 — No PII in logs (fnr, name, address)
- A09 — Audit trail for sensitive operations
- A10 — All errors handled (no ignored returns in Go)
- A10 — Panic recovery in HTTP handlers
- A10 — Error messages sanitized before client responses
Related
| Resource | Use For |
|---|---|
security-review skill | Pre-commit scanning (trivy, zizmor, govulncheck) |
@security-champion-agent | Threat modeling, compliance, Nav security architecture |
@auth-agent | JWT validation, TokenX, ID-porten implementation |
threat-model skill | STRIDE-A analysis for new services |
| OWASP Top 10:2025 | Official category descriptions |
| OWASP Go SCP | Go-specific secure coding guide |
| OWASP CI/CD Top 10 | Pipeline security risks |
| sikkerhet.nav.no | Nav Golden Path |
Boundaries
✅ Always
- Parameterized queries for all SQL
- Resource-level access checks on every data-returning endpoint
- Structured logging without PII
- SHA-pinned GitHub Actions
- Explicit error handling (no ignored errors)
- Dependencies scanned before release
⚠️ Ask First
- Custom cryptographic implementations
- Disabling security features for testing
- Changing authentication or authorizati
Content truncated.
When not to use it
- →When using string-concatenated SQL queries
- →When setting `InsecureSkipVerify: true` in production
- →When including PII in log statements
Limitations
- →The skill provides code-level patterns for Kotlin, Go, Java, and Node.js on NAIS
- →The skill is aligned with the 2025 OWASP Top 10
- →The skill focuses on access control, supply chain, injection, and error handling
How it compares
This skill offers code-level security patterns aligned with OWASP Top 10:2025, providing specific examples for preventing common vulnerabilities like IDOR, SSRF, and SQL injection, unlike general security advice.
Compared to similar skills
security-owasp side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| security-owasp (this skill) | 0 | 2mo | No flags | Intermediate |
| springboot-security | 5 | 5mo | No flags | Intermediate |
| asl-java-implement-rule-authz | 0 | 2mo | No flags | Advanced |
| workflow-orchestration-patterns | 10 | 2mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by navikt
View all by navikt →You might also like
springboot-security
affaan-m
Spring Security best practices for authn/authz, validation, CSRF, secrets, headers, rate limiting, and dependency security in Java Spring Boot services.
asl-java-implement-rule-authz
ChapmanRichard
Use when: 需要在 LeaveSystem_Backend_Java 中实现认证与鉴权规则,覆盖 Header/JWT、RBAC、资源归属和默认拒绝。关键词: Java 鉴权, Spring Boot, RBAC, Authorization, 资源级权限
workflow-orchestration-patterns
wshobson
Design durable workflows with Temporal for distributed systems. Covers workflow vs activity separation, saga patterns, state management, and determinism constraints. Use when building long-running processes, distributed transactions, or microservice orchestration.
backend-microservice-development
TencentBlueKing
后端微服务开发规范,涵盖目录结构、分层架构(API/Service/DAO)、依赖注入、配置管理、Spring Boot 最佳实践。当用户进行后端开发、创建新微服务、编写 Kotlin/Java 代码或设计服务架构时使用。
jackson-security
benchflow-ai
Security considerations for Jackson JSON deserialization in Java applications. Covers timing of validation, raw input interception, and common deserialization attack patterns.
auth-implementation-patterns
sickn33
Master authentication and authorization patterns including JWT, OAuth2, session management, and RBAC to build secure, scalable access control systems. Use when implementing auth systems, securing APIs, or debugging security issues.