Skip to content

Code Guard rules ​

Code Guard has 38 rules in four groups. Each one shows the code an agent wrote that Code Guard stops (Flagged) and the code it asks for instead (Fixed). Rules marked Free are in every plan; the Student, Pro and Team plans include them all. You can turn any rule off on the Code Guard page.

RuleSeverityLanguagesPlan
Secret written into the codeCriticalEvery fileFree
Memory from new[] is never freedHighC++Free
Raw new without delete or a smart pointerMediumC++Paid plans
malloc without freeHighC, C++Free
gets() can always overflowCriticalC, C++Free
strcpy or strcat without a size limitHighC, C++Paid plans
sprintf without a size limitHighC, C++Paid plans
scanf("%s") without a widthHighC, C++Paid plans
A variable used as the printf formatHighC, C++Paid plans
mem::forget leaks the valueMediumRustPaid plans
Box::leak is never freedMediumRustPaid plans
SQL built by joining stringsCriticalPython, JavaScript / TypeScript, Java, C#, PHP, Go, Ruby, KotlinFree
SQL built with an f-string or % formattingCriticalPythonFree
SQL built with a template stringCriticalJavaScript / TypeScriptFree
SQL built with fmt.SprintfCriticalGoFree
Request data straight into SQLCriticalPHPFree
include or require with request dataCriticalPHPFree
eval or execHighPythonPaid plans
eval or new FunctionHighJavaScript / TypeScript, PHPPaid plans
subprocess with shell=True or os.systemHighPythonPaid plans
Shell command built from a variableHighJavaScript / TypeScriptPaid plans
Runtime.exec with a joined stringHighJava, KotlinPaid plans
system() runs a shellMediumC, C++Paid plans
pickle.loads on dataHighPythonPaid plans
yaml.load without SafeLoaderHighPythonPaid plans
innerHTML set from a variableMediumJavaScript / TypeScriptPaid plans
dangerouslySetInnerHTML without sanitizingHighJavaScript / TypeScriptPaid plans
Certificate checks switched offHighPython, JavaScript / TypeScript, GoPaid plans
Every certificate or host name acceptedHighJava, Kotlin, C#Paid plans
Permissions 777HighC, C++, Python, JavaScript / TypeScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, ShellPaid plans
MD5 or SHA-1 for passwordsHighC, C++, Python, JavaScript / TypeScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, ShellPaid plans
Predictable random numbers for a secretMediumPython, JavaScript / TypeScript, Go, Java, PHP, Ruby, C#Paid plans
ECB encryption modeHighC, C++, Python, JavaScript / TypeScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, ShellPaid plans
JWT signature not checkedCriticalPython, JavaScript / TypeScript, Java, GoFree
Flask debug mode onHighPythonPaid plans
CORS open to every siteMediumJavaScript / TypeScript, Python, Go, Java, PHP, C#Paid plans
CSRF protection switched offMediumPython, Java, KotlinPaid plans
Downloaded script piped into a shellMediumShellPaid plans

Secrets ​

Keys, tokens and passwords written into the code.

Secret written into the code ​

Critical hardcoded-secret · Every file · Free

Why it matters. Anyone who can read the repository, its history or a build can use the key; deleting it later doesn't remove it from git history.

How to fix it. Read it from an environment variable or a secret manager (os.environ["API_KEY"], process.env.API_KEY) and keep the value out of the repository, for example in an ignored .env file.

python
API_SECRET = "q8Xz2LmN4vB7rT1wK9pY3sD6hJ5c"
python
API_SECRET = os.environ["API_SECRET"]

Memory ​

Leaks and buffer overflows in C, C++ and Rust.

Memory from new[] is never freed ​

High cpp-new-array-leak · C++ · Free

Why it matters. The array is allocated with new[] but the file never calls delete[], so the memory leaks every time this runs.

How to fix it. Let an owner free it: std::vector<T>, or auto p = std::make_unique<T[]>(n). If you must keep raw new[], pair it with delete[].

cpp
void load() {
    int* buffer = new int[1000];
    fill(buffer);
}
cpp
void load() {
    auto buffer = std::make_unique<int[]>(1000);
    fill(buffer.get());
}

Raw new without delete or a smart pointer ​

Medium cpp-raw-new · C++ · Paid plans

Why it matters. An object created with new and kept in a raw pointer is freed only if every path reaches a delete; an early return or an exception leaks it.

How to fix it. Use std::make_unique<T>(...) (or std::make_shared) so the object is freed when its owner goes away (RAII).

cpp
Widget* w = new Widget(config);
w->run();
cpp
auto w = std::make_unique<Widget>(config);
w->run();

malloc without free ​

High c-malloc-leak · C, C++ · Free

Why it matters. Memory from malloc, calloc or realloc is allocated but the file never calls free, so it leaks.

How to fix it. free() it on every path once you're done (a single cleanup label in C helps). In C++, use std::vector or std::unique_ptr instead.

c
char* name = malloc(64);
strncpy(name, input, 63);
return strlen(name);
c
char* name = malloc(64);
strncpy(name, input, 63);
size_t n = strlen(name);
free(name);
return n;

gets() can always overflow ​

Critical c-gets · C, C++ · Free

Why it matters. gets() has no way to know the buffer's size, so any long enough input overwrites memory. It was removed from C11.

How to fix it. Use fgets(buffer, sizeof buffer, stdin), or std::getline in C++.

c
char line[128];
gets(line);
c
char line[128];
fgets(line, sizeof line, stdin);

strcpy or strcat without a size limit ​

High c-strcpy · C, C++ · Paid plans

Why it matters. strcpy and strcat copy until the source ends, whatever the destination's size, which overflows the buffer on long input.

How to fix it. Use snprintf(dst, sizeof dst, "%s", src) or strlcpy, or std::string in C++.

c
char path[64];
strcpy(path, user_input);
c
char path[64];
snprintf(path, sizeof path, "%s", user_input);

sprintf without a size limit ​

High c-sprintf · C, C++ · Paid plans

Why it matters. sprintf writes as much as the format produces, past the end of the buffer if it's too small.

How to fix it. Use snprintf(buffer, sizeof buffer, ...), or std::format / std::ostringstream in C++.

c
char msg[32];
sprintf(msg, "Hello %s", name);
c
char msg[32];
snprintf(msg, sizeof msg, "Hello %s", name);

scanf("%s") without a width ​

High c-scanf-string · C, C++ · Paid plans

Why it matters. %s with no width reads a word of any length into a fixed buffer.

How to fix it. Give the width, one less than the buffer: scanf("%63s", name) for char name[64], or use fgets.

c
char name[64];
scanf("%s", name);
c
char name[64];
scanf("%63s", name);

A variable used as the printf format ​

High c-format-string · C, C++ · Paid plans

Why it matters. If the text contains %n or %x, printf reads or writes memory it shouldn't (a format string attack).

How to fix it. Pass a fixed format: printf("%s", text).

c
printf(message);
c
printf("%s", message);

mem::forget leaks the value ​

Medium rust-mem-forget · Rust · Paid plans

Why it matters. std::mem::forget never runs the value's destructor, so the memory, file or lock it holds is never released.

How to fix it. Let the value drop. If it must outlive this scope, store it; if it crosses an FFI boundary, use ManuallyDrop or Box::into_raw and free it on the other side.

rust
let file = File::open(path)?;
std::mem::forget(file);
rust
let file = File::open(path)?;
drop(file);

Box::leak is never freed ​

Medium rust-box-leak · Rust · Paid plans

Why it matters. Box::leak gives a 'static reference by never freeing the memory; in a loop or per request it grows without bound.

How to fix it. Keep the Box (or an Arc) and borrow from it. Use leak only for a value created once at startup.

rust
let name: &'static str = Box::leak(input.into_boxed_str());
rust
let name: Arc<str> = Arc::from(input);

Injection ​

Outside input reaching SQL, a shell, eval or the page's HTML.

SQL built by joining strings ​

Critical sql-string-concat · Python, JavaScript / TypeScript, Java, C#, PHP, Go, Ruby, Kotlin · Free

Why it matters. Adding a value to the query text lets an attacker change the query: ' OR 1=1 -- reads every row (SQL injection).

How to fix it. Use placeholders and pass the values separately: db.query("SELECT * FROM users WHERE id = ?", [id]).

python
const rows = await db.query("SELECT * FROM users WHERE id = " + id);
python
const rows = await db.query("SELECT * FROM users WHERE id = ?", [id]);

SQL built with an f-string or % formatting ​

Critical py-sql-format · Python · Free

Why it matters. Formatting a value into the query text lets an attacker change the query (SQL injection).

How to fix it. Pass the values as parameters: cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)).

python
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
python
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))

SQL built with a template string ​

Critical js-sql-template · JavaScript / TypeScript · Free

Why it matters. A ${value} inside the query text lets an attacker change the query (SQL injection).

How to fix it. Use placeholders: db.query("SELECT * FROM users WHERE id = $1", [id]), or a tagged template your driver escapes (sql...).

tsx
await db.query(`SELECT * FROM users WHERE email = '${email}'`);
tsx
await db.query("SELECT * FROM users WHERE email = $1", [email]);

SQL built with fmt.Sprintf ​

Critical go-sql-sprintf · Go · Free

Why it matters. Formatting a value into the query text lets an attacker change the query (SQL injection).

How to fix it. Use placeholders: db.Query("SELECT * FROM users WHERE id = $1", id).

go
rows, err := db.Query(fmt.Sprintf("SELECT * FROM users WHERE id = %s", id))
go
rows, err := db.Query("SELECT * FROM users WHERE id = $1", id)

Request data straight into SQL ​

Critical php-request-in-sql · PHP · Free

Why it matters. $_GET, $_POST and $_REQUEST come from the visitor; putting them in a query lets them rewrite it (SQL injection).

How to fix it. Use a prepared statement: $stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?'); $stmt->execute([$_GET['id']]);

php
$result = mysqli_query($db, "SELECT * FROM users WHERE id = " . $_GET['id']);
php
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$_GET['id']]);

include or require with request data ​

Critical php-request-include · PHP · Free

Why it matters. Letting the visitor choose the file to include lets them run or read any file on the server.

How to fix it. Map the request value to a fixed list of allowed files, and include only from that list.

php
include($_GET['page'] . '.php');
php
$pages = ['home' => 'home.php', 'about' => 'about.php'];
include($pages[$_GET['page']] ?? 'home.php');

eval or exec ​

High py-eval · Python · Paid plans

Why it matters. eval and exec run any Python they're given; with outside input that is remote code execution.

How to fix it. Parse the data instead: json.loads for JSON, ast.literal_eval for Python literals, a dict of allowed functions for commands.

python
value = eval(request.args["expr"])
python
value = ast.literal_eval(request.args["expr"])

eval or new Function ​

High js-eval · JavaScript / TypeScript, PHP · Paid plans

Why it matters. eval and new Function run any code they're given; with outside input that is code injection.

How to fix it. Parse the data instead (JSON.parse), or look the action up in an object of allowed functions.

tsx
const result = eval(userExpression);
tsx
const result = JSON.parse(userInput);

subprocess with shell=True or os.system ​

High py-shell-true · Python · Paid plans

Why it matters. The command goes through the shell, so a value containing ; rm -rf ~ runs as a second command (command injection).

How to fix it. Pass a list and no shell: subprocess.run(["convert", path, out], check=True).

python
subprocess.run(f"convert {path} out.png", shell=True)
python
subprocess.run(["convert", path, "out.png"], check=True)

Shell command built from a variable ​

High js-exec-interpolated · JavaScript / TypeScript · Paid plans

Why it matters. child_process.exec runs a shell, so a value containing ; rm -rf ~ runs as a second command (command injection).

How to fix it. Use execFile or spawn with an argument list: execFile("git", ["clone", url]).

tsx
exec(`git clone ${url}`);
tsx
execFile("git", ["clone", url]);

Runtime.exec with a joined string ​

High java-runtime-exec · Java, Kotlin · Paid plans

Why it matters. Joining input into the command lets it add arguments or commands of its own.

How to fix it. Use new ProcessBuilder("git", "clone", url) with each argument separate.

java
Runtime.getRuntime().exec("ping " + host);
java
new ProcessBuilder("ping", host).start();

system() runs a shell ​

Medium c-system · C, C++ · Paid plans

Why it matters. system() hands the string to a shell, so any input in it can add commands (command injection).

How to fix it. Run the program directly with execv / posix_spawn and separate arguments.

c
system(command);
c
char* argv[] = {"ls", "-l", NULL};
posix_spawnp(&pid, "ls", NULL, NULL, argv, environ);

pickle.loads on data ​

High py-pickle · Python · Paid plans

Why it matters. Unpickling runs code the data asks for; a crafted file or request is remote code execution.

How to fix it. Use json (or msgpack) for data from outside. Load pickles only from files you wrote yourself.

python
obj = pickle.loads(request.data)
python
obj = json.loads(request.data)

yaml.load without SafeLoader ​

High py-yaml-load · Python · Paid plans

Why it matters. yaml.load with the default loader can build any Python object, which runs code from the YAML.

How to fix it. Use yaml.safe_load(text), or yaml.load(text, Loader=yaml.SafeLoader).

python
config = yaml.load(text)
python
config = yaml.safe_load(text)

innerHTML set from a variable ​

Medium js-inner-html · JavaScript / TypeScript · Paid plans

Why it matters. Text put into innerHTML is parsed as HTML, so a value with <script> or onerror= runs in the page (XSS).

How to fix it. Use textContent for text. For HTML you trust, clean it first with DOMPurify.sanitize().

tsx
element.innerHTML = comment.body;
tsx
element.textContent = comment.body;

dangerouslySetInnerHTML without sanitizing ​

High react-dangerous-html · JavaScript / TypeScript · Paid plans

Why it matters. React renders the string as HTML, so any script or event handler in it runs (XSS).

How to fix it. Render text normally, or wrap the HTML with DOMPurify.sanitize() before passing it.

tsx
<div dangerouslySetInnerHTML={{ __html: post.body }} />
tsx
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(post.body) }} />

Unsafe settings ​

Security switched off: certificate checks, permissions, weak crypto, debug mode.

Certificate checks switched off ​

High tls-verify-off · Python, JavaScript / TypeScript, Go · Paid plans

Why it matters. Without certificate checks anyone on the network can pretend to be the server and read or change the traffic.

How to fix it. Leave verification on. For a private certificate authority, point to its certificate (verify="ca.pem", ca: fs.readFileSync(...)).

python
requests.get(url, verify=False)
python
requests.get(url, verify="/etc/ssl/company-ca.pem")

Every certificate or host name accepted ​

High trust-all-certificates · Java, Kotlin, C# · Paid plans

Why it matters. A verifier that always says yes turns off HTTPS protection: anyone on the network can intercept the connection.

How to fix it. Use the platform's default verification. For a private CA, add it to a trust store instead.

java
conn.setHostnameVerifier((host, session) -> true);
java
// keep the default HostnameVerifier
conn.connect();

Permissions 777 ​

High chmod-777 · C, C++, Python, JavaScript / TypeScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, Shell · Paid plans

Why it matters. 777 lets every user on the machine read, change and run the file, including another service if one is compromised.

How to fix it. Give only what's needed: 755 for programs and folders, 644 for files, 600 for secrets.

c
chmod -R 777 /var/www/uploads
c
chmod -R 755 /var/www/uploads

MD5 or SHA-1 for passwords ​

High weak-password-hash · C, C++, Python, JavaScript / TypeScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, Shell · Paid plans

Why it matters. MD5 and SHA-1 are fast, so a leaked password table is cracked in hours.

How to fix it. Use a password hash: bcrypt, scrypt or Argon2 (argon2-cffi, bcrypt, password_hash() in PHP).

c
hashed = hashlib.md5(password.encode()).hexdigest()
c
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())

Predictable random numbers for a secret ​

Medium weak-random-secret · Python, JavaScript / TypeScript, Go, Java, PHP, Ruby, C# · Paid plans

Why it matters. Math.random, random.random and rand() can be predicted, so tokens, passwords or codes made with them can be guessed.

How to fix it. Use a cryptographic source: crypto.randomUUID() / crypto.getRandomValues, secrets.token_urlsafe(), crypto/rand, SecureRandom, random_bytes().

python
const token = Math.random().toString(36).slice(2);
python
const token = crypto.randomUUID();

ECB encryption mode ​

High ecb-mode · C, C++, Python, JavaScript / TypeScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, Shell · Paid plans

Why it matters. ECB encrypts equal blocks to equal output, so patterns in the data stay visible and blocks can be swapped.

How to fix it. Use an authenticated mode: AES-GCM (or ChaCha20-Poly1305) with a new random nonce each time.

c
cipher = AES.new(key, AES.MODE_ECB)
c
cipher = AES.new(key, AES.MODE_GCM)

JWT signature not checked ​

Critical jwt-no-verify · Python, JavaScript / TypeScript, Java, Go · Free

Why it matters. Without the signature check anyone can write their own token and sign in as any user.

How to fix it. Verify with the expected key and algorithm: jwt.decode(token, key, algorithms=["HS256"]), jwt.verify(token, key).

python
claims = jwt.decode(token, options={"verify_signature": False})
python
claims = jwt.decode(token, key, algorithms=["HS256"])

Flask debug mode on ​

High flask-debug · Python · Paid plans

Why it matters. The debugger page lets anyone who can reach the app run Python on the server.

How to fix it. Turn debug on only through an environment variable in development, never in code that ships.

python
app.run(host="0.0.0.0", debug=True)
python
app.run(host="0.0.0.0", debug=os.environ.get("FLASK_DEBUG") == "1")

CORS open to every site ​

Medium cors-any-origin · JavaScript / TypeScript, Python, Go, Java, PHP, C# · Paid plans

Why it matters. Allowing every origin lets any website call this API from a visitor's browser.

How to fix it. List the sites that may call it: cors({ origin: ["https://app.example.com"] }).

tsx
app.use(cors({ origin: "*" }));
tsx
app.use(cors({ origin: ["https://app.example.com"] }));

CSRF protection switched off ​

Medium csrf-disabled · Python, Java, Kotlin · Paid plans

Why it matters. Without it another site can make a signed-in visitor's browser send requests here (cross-site request forgery).

How to fix it. Keep CSRF protection on for routes that use cookies. Turn it off only for token-authenticated APIs.

python
http.csrf().disable();
python
http.csrf(Customizer.withDefaults());

Downloaded script piped into a shell ​

Medium curl-pipe-shell · Shell · Paid plans

Why it matters. Whatever the server sends runs right away, with no chance to check it; a hijacked or mistyped URL runs its code.

How to fix it. Download to a file, check its checksum or signature, then run it.

bash
curl -fsSL https://example.com/install.sh | sudo bash
bash
curl -fsSLo install.sh https://example.com/install.sh
sha256sum -c install.sh.sha256
bash install.sh