A collection of semgrep rules for my personal projects
0

Configure Feed

Select the types of activity you want to include in your feed.

initial commit

Luca Scherzer (Jul 10, 2026, 9:39 AM +0200) 46468b14

+354
+141
rust/blocking-in-async.yaml
··· 1 + rules: 2 + - id: blocking-command-in-async 3 + message: > 4 + Synchronous `Command::{output,status,wait}()` called inside async fn `$FUNC`. 5 + This blocks the tokio worker thread and stalls all concurrent jobs. 6 + Use `tokio::task::spawn_blocking` to wrap the Command execution. 7 + severity: ERROR 8 + languages: 9 + - rust 10 + patterns: 11 + - pattern-inside: | 12 + async fn $FUNC(...) { ... } 13 + - pattern-not-inside: | 14 + tokio::task::spawn_blocking(move || { ... }) 15 + - pattern-not-inside: | 16 + tokio::task::spawn_blocking(move || ...) 17 + - pattern-not-inside: | 18 + spawn_blocking(move || { ... }) 19 + - pattern-not-inside: | 20 + spawn_blocking(move || ...) 21 + - pattern-not-inside: | 22 + #[tokio::test] 23 + async fn $FUNC(...) { ... } 24 + - pattern-not-inside: | 25 + #[tokio::test(...)] 26 + async fn $FUNC(...) { ... } 27 + - pattern-either: 28 + - pattern: $CMD.output(...) 29 + - pattern: $CMD.status(...) 30 + - pattern: $CMD.wait(...) 31 + - metavariable-regex: 32 + metavariable: $CMD 33 + regex: (?:Command|cmd|command|process|proc)\b 34 + 35 + - id: blocking-reqwest-in-async 36 + message: > 37 + `reqwest::blocking` usage inside async fn `$FUNC`. 38 + This blocks the tokio worker thread. Use the async `reqwest` client instead. 39 + severity: ERROR 40 + languages: 41 + - rust 42 + patterns: 43 + - pattern-inside: | 44 + async fn $FUNC(...) { ... } 45 + - pattern-not-inside: | 46 + #[tokio::test] 47 + async fn $FUNC(...) { ... } 48 + - pattern-not-inside: | 49 + #[tokio::test(...)] 50 + async fn $FUNC(...) { ... } 51 + - pattern-either: 52 + - pattern: reqwest::blocking::$METHOD(...) 53 + - pattern: $CLIENT.$METHOD(...) 54 + - metavariable-regex: 55 + metavariable: $METHOD 56 + regex: (?:blocking|blocking_request) 57 + 58 + - id: blocking-filesystem-in-async 59 + message: > 60 + Synchronous `std::fs::{read,write,create_dir_all,...}` called inside async fn `$FUNC`. 61 + This blocks the tokio worker thread. Use `tokio::fs::*` or `tokio::task::spawn_blocking` instead. 62 + severity: ERROR 63 + languages: 64 + - rust 65 + patterns: 66 + - pattern-inside: | 67 + async fn $FUNC(...) { ... } 68 + - pattern-not-inside: | 69 + tokio::task::spawn_blocking(move || { ... }) 70 + - pattern-not-inside: | 71 + tokio::task::spawn_blocking(move || ...) 72 + - pattern-not-inside: | 73 + spawn_blocking(move || { ... }) 74 + - pattern-not-inside: | 75 + spawn_blocking(move || ...) 76 + - pattern-not-inside: | 77 + #[tokio::test] 78 + async fn $FUNC(...) { ... } 79 + - pattern-not-inside: | 80 + #[tokio::test(...)] 81 + async fn $FUNC(...) { ... } 82 + - pattern-either: 83 + - pattern: std::fs::$FSFUNC(...) 84 + - pattern: std::fs::File::$FILEFUNC(...) 85 + 86 + - id: blocking-thread-sleep-in-async 87 + message: > 88 + `std::thread::sleep(...)` called inside async fn `$FUNC`. 89 + This blocks the tokio worker thread entirely. 90 + Use `tokio::time::sleep(...)` instead. 91 + severity: ERROR 92 + languages: 93 + - rust 94 + patterns: 95 + - pattern-inside: | 96 + async fn $FUNC(...) { ... } 97 + - pattern-not-inside: | 98 + tokio::task::spawn_blocking(move || { ... }) 99 + - pattern-not-inside: | 100 + tokio::task::spawn_blocking(move || ...) 101 + - pattern-not-inside: | 102 + spawn_blocking(move || { ... }) 103 + - pattern-not-inside: | 104 + spawn_blocking(move || ...) 105 + - pattern-not-inside: | 106 + #[tokio::test] 107 + async fn $FUNC(...) { ... } 108 + - pattern-not-inside: | 109 + #[tokio::test(...)] 110 + async fn $FUNC(...) { ... } 111 + - pattern: std::thread::sleep(...) 112 + 113 + - id: blocking-std-net-in-async 114 + message: > 115 + Blocking `std::net::{TcpStream,TcpListener,UdpSocket}` called inside async fn `$FUNC`. 116 + This blocks the tokio worker thread. Use `tokio::net::*` equivalents instead. 117 + severity: ERROR 118 + languages: 119 + - rust 120 + patterns: 121 + - pattern-inside: | 122 + async fn $FUNC(...) { ... } 123 + - pattern-not-inside: | 124 + tokio::task::spawn_blocking(move || { ... }) 125 + - pattern-not-inside: | 126 + tokio::task::spawn_blocking(move || ...) 127 + - pattern-not-inside: | 128 + spawn_blocking(move || { ... }) 129 + - pattern-not-inside: | 130 + spawn_blocking(move || ...) 131 + - pattern-not-inside: | 132 + #[tokio::test] 133 + async fn $FUNC(...) { ... } 134 + - pattern-not-inside: | 135 + #[tokio::test(...)] 136 + async fn $FUNC(...) { ... } 137 + - pattern-either: 138 + - pattern: std::net::TcpStream::connect(...) 139 + - pattern: std::net::TcpListener::bind(...) 140 + - pattern: std::net::UdpSocket::bind(...) 141 + - pattern: std::net::TcpStream::connect_timeout(...)
+41
rust/code-quality.yaml
··· 1 + rules: 2 + - id: print-instead-of-tracing 3 + message: > 4 + `println!`/`eprintln!` bypasses the tracing/logging subsystem and 5 + won't respect log levels or TUI silent mode. 6 + Use `tracing::info!`, `tracing::error!`, etc. instead. 7 + severity: WARNING 8 + languages: 9 + - rust 10 + paths: 11 + exclude: 12 + - "**/crates/*/src/bin/*.rs" 13 + - "**/tests/**" 14 + - "**/test_utils*" 15 + patterns: 16 + - pattern-either: 17 + - pattern: println!(...) 18 + - pattern: eprintln!(...) 19 + 20 + - id: lock-unwrap 21 + message: > 22 + `.lock().unwrap()` panics if the mutex is poisoned. 23 + Consider `.lock().expect("lock poisoned")` for a clearer blame path 24 + or handle poison explicitly with `.lock().map_err(...)`. 25 + severity: WARNING 26 + languages: 27 + - rust 28 + pattern: $LOCK.lock().unwrap() 29 + 30 + - id: discarded-filesystem-error 31 + message: > 32 + Filesystem operation result discarded with `let _ =`. 33 + If cleanup fails the error is silently swallowed. 34 + Consider: `if let Err(e) = ... { tracing::warn!(...) }`. 35 + severity: WARNING 36 + languages: 37 + - rust 38 + patterns: 39 + - pattern-either: 40 + - pattern: let _ = std::fs::$FSFUNC(...) 41 + - pattern: let _ = tokio::fs::$FUNC(...)
+91
typescript/react-best-practices.yaml
··· 1 + rules: 2 + - id: dangerously-set-inner-html 3 + message: > 4 + `dangerouslySetInnerHTML` exposes the app to XSS attacks. 5 + Prefer React's built-in rendering or use a sanitization library 6 + like DOMPurify if raw HTML is unavoidable. 7 + severity: ERROR 8 + languages: 9 + - typescript 10 + - javascript 11 + pattern: dangerouslySetInnerHTML=$VALUE 12 + paths: 13 + include: 14 + - "**/web/src/**/*.tsx" 15 + - "**/web/src/**/*.jsx" 16 + 17 + - id: missing-key-in-map 18 + message: > 19 + Missing `key` prop on JSX element returned by `.map()`. 20 + Add a unique `key` prop (e.g., `key={item.id}`) to each rendered element. 21 + severity: ERROR 22 + languages: 23 + - typescript 24 + patterns: 25 + - pattern-either: 26 + # No parens, no attributes 27 + - patterns: 28 + - pattern: | 29 + $ARR.map($FUNC => <$TAG>$...BODY</$TAG>) 30 + - pattern-not: | 31 + $ARR.map($FUNC => <$TAG key={...}>$...BODY</$TAG>) 32 + - pattern-not: | 33 + $ARR.map($FUNC => <$TAG key={...} $...POST>$...BODY</$TAG>) 34 + - pattern-not: | 35 + $ARR.map($FUNC => <$TAG $...PRE key={...}>$...BODY</$TAG>) 36 + - pattern-not: | 37 + $ARR.map($FUNC => <$TAG $...PRE key={...} $...POST>$...BODY</$TAG>) 38 + # No parens, with attributes 39 + - patterns: 40 + - pattern: | 41 + $ARR.map($FUNC => <$TAG $...ATTRS>$...BODY</$TAG>) 42 + - pattern-not: | 43 + $ARR.map($FUNC => <$TAG key={...}>$...BODY</$TAG>) 44 + - pattern-not: | 45 + $ARR.map($FUNC => <$TAG key={...} $...POST>$...BODY</$TAG>) 46 + - pattern-not: | 47 + $ARR.map($FUNC => <$TAG $...PRE key={...}>$...BODY</$TAG>) 48 + - pattern-not: | 49 + $ARR.map($FUNC => <$TAG $...PRE key={...} $...POST>$...BODY</$TAG>) 50 + # Parenthesized body, no attributes 51 + - patterns: 52 + - pattern: | 53 + $ARR.map($FUNC => (<$TAG>$...BODY</$TAG>)) 54 + - pattern-not: | 55 + $ARR.map($FUNC => (<$TAG key={...}>$...BODY</$TAG>)) 56 + - pattern-not: | 57 + $ARR.map($FUNC => (<$TAG key={...} $...POST>$...BODY</$TAG>)) 58 + - pattern-not: | 59 + $ARR.map($FUNC => (<$TAG $...PRE key={...}>$...BODY</$TAG>)) 60 + - pattern-not: | 61 + $ARR.map($FUNC => (<$TAG $...PRE key={...} $...POST>$...BODY</$TAG>)) 62 + # Parenthesized body, with attributes 63 + - patterns: 64 + - pattern: | 65 + $ARR.map($FUNC => (<$TAG $...ATTRS>$...BODY</$TAG>)) 66 + - pattern-not: | 67 + $ARR.map($FUNC => (<$TAG key={...}>$...BODY</$TAG>)) 68 + - pattern-not: | 69 + $ARR.map($FUNC => (<$TAG key={...} $...POST>$...BODY</$TAG>)) 70 + - pattern-not: | 71 + $ARR.map($FUNC => (<$TAG $...PRE key={...}>$...BODY</$TAG>)) 72 + - pattern-not: | 73 + $ARR.map($FUNC => (<$TAG $...PRE key={...} $...POST>$...BODY</$TAG>)) 74 + paths: 75 + include: 76 + - "**/web/src/**/*.tsx" 77 + 78 + - id: array-index-as-key 79 + message: > 80 + Using array index as `key` prop (`key={$I}`) causes subtle bugs 81 + when items are reordered, filtered, or mutated. 82 + Use a stable unique identifier instead (e.g., `key={item.id}`). 83 + severity: WARNING 84 + languages: 85 + - typescript 86 + patterns: 87 + - pattern-inside: $ARR.map(($F, $I) => ...) 88 + - pattern: key={$I} 89 + paths: 90 + include: 91 + - "**/web/src/**/*.tsx"
+81
typescript/ts-code-quality.yaml
··· 1 + rules: 2 + - id: console-log 3 + message: > 4 + `console.log(...)` leaves debug output in production code. 5 + Remove it or use `console.error`/`console.warn` for user-visible messages. 6 + severity: WARNING 7 + languages: 8 + - javascript 9 + - typescript 10 + pattern: console.log(...) 11 + paths: 12 + include: 13 + - "**/web/src/**/*.ts" 14 + - "**/web/src/**/*.tsx" 15 + - "**/web/src/**/*.js" 16 + - "**/web/src/**/*.jsx" 17 + 18 + - id: empty-catch-clause 19 + message: > 20 + Empty `catch` block silently swallows errors. 21 + Log the error with `console.error`, or add a comment explaining why 22 + the error is safe to ignore. 23 + severity: WARNING 24 + languages: 25 + - javascript 26 + - typescript 27 + pattern-either: 28 + - pattern: "catch {}" 29 + - pattern: "catch ($E) {}" 30 + paths: 31 + include: 32 + - "**/web/src/**/*.ts" 33 + - "**/web/src/**/*.tsx" 34 + 35 + - id: any-type 36 + message: > 37 + Using `any` defeats TypeScript's type safety. 38 + Prefer `unknown` with type narrowing, or define a proper interface. 39 + severity: WARNING 40 + languages: 41 + - typescript 42 + patterns: 43 + - pattern-either: 44 + - pattern: "$X: any" 45 + - pattern: "$X as any" 46 + paths: 47 + include: 48 + - "**/web/src/**/*.ts" 49 + - "**/web/src/**/*.tsx" 50 + 51 + - id: non-null-assertion 52 + message: > 53 + Non-null assertion (`!`) can cause runtime errors if the value is nullish. 54 + Prefer optional chaining (`?.`) or explicit null checks with `if`. 55 + severity: WARNING 56 + languages: 57 + - typescript 58 + patterns: 59 + - pattern-either: 60 + - pattern: $X!.$Y 61 + - pattern: $X![$Y] 62 + - pattern-not: $X !== $Y 63 + - pattern-not: $X != $Y 64 + paths: 65 + include: 66 + - "**/web/src/**/*.ts" 67 + - "**/web/src/**/*.tsx" 68 + 69 + - id: ts-expect-error-without-reason 70 + message: > 71 + `@ts-expect-error` should include a comment explaining why the error is expected. 72 + Add a reason after the directive, e.g., 73 + `// @ts-expect-error: <reason>`. 74 + severity: WARNING 75 + languages: 76 + - typescript 77 + pattern-regex: // @ts-expect-error\s*$ 78 + paths: 79 + include: 80 + - "**/web/src/**/*.ts" 81 + - "**/web/src/**/*.tsx"