
Code Reviewer
Review C code against universal and language-specific rules to eliminate security smells and unsafe patterns before merge.
Overview
Code Reviewer is an agent skill most often used in Ship (also Build) that reviews C source against universal and C language rules to remove security smells and unsafe APIs.
Install
npx skills add https://github.com/alirezarezvani/claude-skills --skill code-reviewerWhat is this skill?
- Applies rules/universal.md plus languages/c.md for structured C review
- Targets bounds-aware I/O (fgets, snprintf, strncpy, bounded scanf)
- Flags unchecked malloc and unsafe string/format patterns
- Demonstrates refactor from smell-heavy sample to zero-detector clean variant
- Keeps same program behavior while removing common C security footguns
Adoption & trust: 879 installs on skills.sh; 17.5k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your C changes compile but still hide buffer overflows, unchecked allocations, and injection-prone calls you do not catch in casual review.
Who is it for?
Indie developers shipping small C utilities, bindings, or security-sensitive native code with markdown-encoded standards.
Skip if: Large polyglot monorepos needing org-wide PR bots, or teams that do not use C at all.
When should I use this skill?
User wants C code reviewed against universal and C language rule packs, or refactored to remove documented smell patterns.
What do I get? / Deliverables
Rule-aligned review feedback and refactored patterns such as bounded I/O, checked malloc, and literal-only system() usage ready for merge.
- Issue list mapped to universal and C rules
- Suggested or applied refactors with safer I/O and memory patterns
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Ship/review is the canonical shelf because the skill produces review-grade refactors aligned to rule packs, typically right before merge or release. Review subphase matches detector-driven passes over unsafe input, allocation, and command execution patterns in C.
Where it fits
Scan new C module changes for strncpy and scanf bounds issues while implementing a native helper.
Run a final detector-aligned review on a PR that touches allocation and input parsing before merge.
How it compares
Rule-pack-driven C review in-chat versus running a separate commercial SAST suite for every commit.
Common Questions / FAQ
Who is code-reviewer for?
Solo builders and small teams writing C who want agent-assisted review tied to universal.md and languages/c.md style rules.
When should I use code-reviewer?
During Build while editing C modules, and during Ship before merging PRs or tagging releases when you need a security-focused pass on strings, memory, and system calls.
Is code-reviewer safe to install?
It reads your source files during review; check the Security Audits panel on this Prism page and avoid pointing it at secrets embedded in code.
SKILL.md
READMESKILL.md - Code Reviewer
/* * sample_c_clean.c — sample_c_smells.c refactored per * rules/universal.md + languages/c.md. Same surface area, zero * detector hits. */ #include <stdio.h> #include <stdlib.h> #include <string.h> void safe_input(void) { char buf[64]; /* fgets is bounds-aware */ if (fgets(buf, sizeof(buf), stdin) == NULL) { return; } char dest[10]; /* strncpy with explicit bound + manual null-terminate */ strncpy(dest, buf, sizeof(dest) - 1); dest[sizeof(dest) - 1] = '\0'; /* strncat with remaining-space bound */ size_t room = sizeof(dest) - strlen(dest) - 1; strncat(dest, "world", room); char msg[100]; /* snprintf is bounds-aware */ snprintf(msg, sizeof(msg), "%s says hello", buf); /* Format string is a literal; buf is an argument */ printf("%s\n", buf); char name[32]; /* %s with explicit width prevents overflow */ scanf("%31s", name); } void checked_alloc(int n) { /* malloc result is NULL-checked before any dereference */ char *buf = malloc(n); if (buf == NULL) { return; } buf[0] = 'x'; buf[1] = 'y'; strncpy(buf, "ok", n - 1); free(buf); buf = NULL; printf("done\n"); } void run_safe_cmd(void) { /* system() with a string literal — no command-injection surface */ system("ls -la"); } int main(int argc, char *argv[]) { (void)argc; (void)argv; safe_input(); checked_alloc(100); run_safe_cmd(); return 0; } /* * sample_c_smells.c — labelled instances of every C-specific pattern * the code-reviewer skill flags. Every smell is annotated inline with * its CWE and the rule from languages/c.md. * * Refactored counterpart: sample_c_clean.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> void unsafe_input(void) { char buf[64]; /* RULE: banned function gets() — CWE-242, no bounds check */ gets(buf); char dest[10]; /* RULE: banned function strcpy() — no bounds check */ strcpy(dest, buf); /* RULE: banned function strcat() — no bounds check */ strcat(dest, "world"); char msg[100]; /* RULE: banned function sprintf() — no bounds check */ sprintf(msg, "%s says hello", buf); /* RULE: format-string vulnerability — CWE-134, buf controls format */ printf(buf); char name[32]; /* RULE: unbounded scanf — %s without width, CWE-120 */ scanf("%s", name); } void leaky_alloc(int n) { /* RULE: malloc result not NULL-checked within 5 lines — CWE-690 */ char *buf = malloc(n); buf[0] = 'x'; buf[1] = 'y'; strcpy(buf, "leak"); /* RULE: free without zeroing pointer — CWE-416 dangling */ free(buf); printf("done\n"); } void run_user_cmd(const char *cmd_from_user) { /* RULE: system() with non-literal argument — CWE-78 command injection */ system(cmd_from_user); } int main(int argc, char *argv[]) { if (argc > 1) { unsafe_input(); leaky_alloc(100); run_user_cmd(argv[1]); } return 0; } // Sample C# file showing the fixed version of sample_csharp_smells.cs. // Same shape, but every smell has been resolved per the patterns documented // in rules/universal.md and languages/csharp.md. // // Run: // python scripts/code_quality_checker.py assets/sample_csharp_clean.cs // // Expected: no HIGH C#-specific smells flagged. using System; using System.Net.Http; using System.Threading.Tasks; using System.Data.SqlClient; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Sample { public class DbOptions { // FIX: connection string from configuration, never inlined. public string ConnectionString { get; init; } = ""; } public class UserService { private readonly string _connectionString; private readonly HttpClient _httpClient; private readonly ILogger<UserService> _logger; // FIX: IHttpClientFactory + IOptions, no hardcoded secrets, no `new