.claude/skills/arch-security-review/SKILL.md
Use when reviewing code for security vulnerabilities, implementing authorization, or ensuring data protection.
npx skillsauth add CongDon1207/AGENTS.md security-reviewInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
// :x: VULNERABLE - No authorization check
[HttpGet("{id}")]
public async Task<Employee> Get(string id)
=> await repo.GetByIdAsync(id);
// :white_check_mark: SECURE - Authorization enforced
[HttpGet("{id}")]
[PlatformAuthorize(Roles.Manager, Roles.Admin)]
public async Task<Employee> Get(string id)
{
var employee = await repo.GetByIdAsync(id);
// Verify access to this specific resource
if (employee.CompanyId != RequestContext.CurrentCompanyId())
throw new UnauthorizedAccessException();
return employee;
}
// :x: VULNERABLE - Storing plain text secrets
var apiKey = config["ApiKey"];
await SaveToDatabase(apiKey);
// :white_check_mark: SECURE - Encrypt sensitive data
var encryptedKey = encryptionService.Encrypt(apiKey);
await SaveToDatabase(encryptedKey);
// Use secure configuration
var apiKey = config.GetValue<string>("ApiKey"); // From Azure Key Vault
// :x: VULNERABLE - SQL Injection
var sql = $"SELECT * FROM Users WHERE Name = '{name}'";
await context.Database.ExecuteSqlRawAsync(sql);
// :white_check_mark: SECURE - Parameterized query
await context.Users.Where(u => u.Name == name).ToListAsync();
// Or if raw SQL needed:
await context.Database.ExecuteSqlRawAsync(
"SELECT * FROM Users WHERE Name = @p0", name);
// :x: VULNERABLE - No rate limiting
[HttpPost("login")]
public async Task<IActionResult> Login(LoginRequest request)
=> await authService.Login(request);
// :white_check_mark: SECURE - Rate limiting applied
[HttpPost("login")]
[RateLimit(MaxRequests = 5, WindowSeconds = 60)]
public async Task<IActionResult> Login(LoginRequest request)
=> await authService.Login(request);
// :x: VULNERABLE - Detailed errors in production
app.UseDeveloperExceptionPage(); // Exposes stack traces
// :white_check_mark: SECURE - Generic errors in production
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseExceptionHandler("/Error");
# Check for vulnerable packages
dotnet list package --vulnerable
# Update vulnerable packages
dotnet outdated
// :x: VULNERABLE - Weak password policy
if (password.Length >= 4) { }
// :white_check_mark: SECURE - Strong password policy
public class PasswordPolicy
{
public bool Validate(string password)
{
return password.Length >= 12
&& password.Any(char.IsUpper)
&& password.Any(char.IsLower)
&& password.Any(char.IsDigit)
&& password.Any(c => !char.IsLetterOrDigit(c));
}
}
// :x: VULNERABLE - No validation of external data
var userData = await externalApi.GetUserAsync(id);
await SaveToDatabase(userData);
// :white_check_mark: SECURE - Validate external data
var userData = await externalApi.GetUserAsync(id);
var validation = userData.Validate();
if (!validation.IsValid)
throw new ValidationException(validation.Errors);
await SaveToDatabase(userData);
// :x: VULNERABLE - Logging sensitive data
Logger.LogInformation("User login: {Email} {Password}", email, password);
// :white_check_mark: SECURE - Redact sensitive data
Logger.LogInformation("User login: {Email}", email);
// Never log passwords, tokens, or PII
// :x: VULNERABLE - User-controlled URL
var url = request.WebhookUrl;
await httpClient.GetAsync(url); // Could access internal services
// :white_check_mark: SECURE - Validate and restrict URLs
if (!IsAllowedUrl(request.WebhookUrl))
throw new SecurityException("Invalid webhook URL");
private bool IsAllowedUrl(string url)
{
var uri = new Uri(url);
return AllowedDomains.Contains(uri.Host)
&& uri.Scheme == "https";
}
[ApiController]
[Route("api/[controller]")]
[PlatformAuthorize] // Require authentication
public class EmployeeController : PlatformBaseController
{
[HttpPost]
[PlatformAuthorize(Roles.Admin, Roles.Manager)] // Role-based
public async Task<IActionResult> Create(...)
}
protected override async Task<PlatformValidationResult<T>> ValidateRequestAsync(
PlatformValidationResult<T> validation, CancellationToken ct)
{
return await validation
// Check role
.And(_ => RequestContext.HasRole(Roles.Admin), "Admin role required")
// Check company access
.And(_ => entity.CompanyId == RequestContext.CurrentCompanyId(),
"Access denied: different company")
// Check ownership
.And(_ => entity.OwnerId == RequestContext.UserId() ||
RequestContext.HasRole(Roles.Admin),
"Access denied: not owner");
}
// Always filter by company/user context
var employees = await repo.GetAllAsync(
e => e.CompanyId == RequestContext.CurrentCompanyId()
&& (e.IsPublic || e.OwnerId == RequestContext.UserId()));
public class SensitiveDataHandler
{
// Encrypt at rest
public string EncryptForStorage(string plainText)
=> encryptionService.Encrypt(plainText);
// Mask for display
public string MaskEmail(string email)
{
var parts = email.Split('@');
return $"{parts[0][0]}***@{parts[1]}";
}
// Never log sensitive data
public void LogUserAction(User user)
{
Logger.LogInformation("User action: {UserId}", user.Id);
// NOT: Logger.Log("User: {Email} {Phone}", user.Email, user.Phone);
}
}
public async Task<IActionResult> Upload(IFormFile file)
{
// Validate file type
var allowedTypes = new[] { ".pdf", ".docx", ".xlsx" };
var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
if (!allowedTypes.Contains(extension))
return BadRequest("Invalid file type");
// Validate file size
if (file.Length > 10 * 1024 * 1024) // 10MB
return BadRequest("File too large");
// Scan for malware (if available)
if (!await antivirusService.ScanAsync(file))
return BadRequest("File rejected by security scan");
// Generate safe filename
var safeFileName = $"{Guid.NewGuid()}{extension}";
// Save to isolated storage
await fileService.SaveAsync(file, safeFileName);
return Ok();
}
# .NET vulnerability scan
dotnet list package --vulnerable
# Outdated packages
dotnet outdated
# Secret scanning
grep -r "password\|secret\|apikey" --include="*.cs" --include="*.json"
# Hardcoded credentials
grep -r "Password=\"" --include="*.cs"
grep -r "connectionString.*password" --include="*.json"
:x: Trusting client input
var isAdmin = request.IsAdmin; // User-supplied!
:x: Exposing internal errors
catch (Exception ex) { return BadRequest(ex.ToString()); }
:x: Hardcoded secrets
var apiKey = "sk_live_xxxxx";
:x: Insufficient logging
// No audit trail for sensitive operations
await DeleteAllUsers();
development
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications, OR when they provide screenshots/images/designs to replicate or draw inspiration from. For screenshot inputs, extracts design guidelines first using ai-multimodal analysis, then implements code following those guidelines. Generates creative, polished code that avoids generic AI aesthetics.
development
Use when the user asks to investigate, understand, explore, or explain how a feature works, asks about existing logic, or wants to understand code flow. Triggers on keywords like "how does", "explain", "investigate", "understand", "what does", "where is", "how works", "logic flow", "trace", "explore feature".
development
Use when the user asks to implement a new feature, enhancement, add functionality, build something new, or create new capabilities. Triggers on keywords like "implement", "add feature", "build", "create new", "develop", "enhancement".
development
Use when the user asks to generate comprehensive feature documentation with verified test cases, create feature README with code evidence, or document a complete feature with test verification. Triggers on keywords like "feature documentation", "document feature", "comprehensive docs", "feature README", "test verification", "verified documentation".