InterLAB tools · 42 evidence-based rules · read-only

Code reviewer, incl. AI-written code

An independent read-only pull request review: 42 published rules on security, migrations, tests, architecture and reliability. Every finding has the file and line, a code excerpt, an explanation and a way to verify it. The code is never changed or executed.

Free, no sign-up

git diff, git format-patch or a GitHub/GitLab PR .diff/.patch. The code is not executed, changed or sent anywhere.

Project context

Rule packs switch on automatically from signals in the diff. You can force them on or off.

No signals found — pack not applied. Signals: .sql, migrations, pg/psycopg/prisma

No signals found — pack not applied. Signals: supabase/ directory, @supabase/*, SUPABASE_*

No signals found — pack not applied. Signals: *.rules, firebase.json, firebase

No signals found — pack not applied. Signals: app/**/page|route, next.config, "use client", next/*

Languages

Nothing selected — all languages are checked by file extension. If you pick languages, rules for the others are skipped.

How the reviewer works

  1. Diff

    Paste a unified diff (git diff, git format-patch, a GitHub or GitLab PR .diff/.patch) or upload the file.

  2. Project context

    Rule packs for PostgreSQL, Supabase, Firebase and the Next.js App Router switch on automatically from signals in the diff (PostgreSQL — .sql, migrations, pg/psycopg/prisma; Supabase — supabase/ directory, @supabase/*, SUPABASE_*; Firebase — *.rules, firebase.json, firebase; Next.js App Router — app/**/page|route, next.config, "use client", next/*); you can force them on or off. You can also limit the check to some languages.

  3. Rules

    Each rule looks at added lines (exceptions are stated) and reports the file, the new-version line, an excerpt with context, why it matters and how to verify. There are no auto-fixes — a person decides.

  4. Reviewer decision

    A finding gets “to fix”, “accepted risk” or “false positive”, a note and a name. Decisions survive a re-check: the finding key is built from the rule, file and line text, not the line number.

  5. Export

    Markdown for a PR comment, PDF via print, JSON to come back to the review, and SARIF 2.1.0 for GitHub code scanning.

Rules

The tables below are generated from the same code as the check — rules v1.0 (2026-10-13). Severity: critical, high, medium, low, info.

CR-SEC-001

What
Looks like a secret in an added line
How it is detected
Key patterns (AWS, GitHub, GitLab, Slack, Stripe, Google, Anthropic, OpenAI, JWT, Telegram, private keys, connection strings with a password) and assignments like password=… (placeholders such as process.env, ${VAR}, changeme are ignored).
Severity
critical
How to verify
Check whether the value is real. If so, revoke and reissue the key, move it to environment variables or a secret store, and clean the history.

CR-SEC-002

What
A .env file is added or changed in the repository
How it is detected
A .env, .env.local, .env.production or similar file (except .env.example/.sample/.template) is added or changed.
Severity
high
How to verify
Make sure the file is in .gitignore and only an .env.example without values is committed. If the values are real, rotate them.

CR-SEC-003

What
Code executed from a string (eval and friends)
How it is detected
JS/TS: eval(), new Function(), setTimeout/setInterval with a string; Python: eval()/exec(); PHP, Ruby: eval().
Severity
high
How to verify
Trace where the string comes from. eval can usually be replaced by JSON parsing, a function lookup table or a safe expression parser.

CR-SEC-004

What
Shell command built from variables
How it is detected
child_process exec/execSync with a template string or concatenation, spawn/execFile with shell: true; subprocess with shell=True, os.system/os.popen with interpolation; exec.Command("sh", "-c", …); PHP shell_exec/system with a variable; Ruby backticks with #{}.
Severity
high
How to verify
Pass arguments as an array (execFile/spawn without a shell, subprocess.run([...])) and check whether the value can come from a user.

CR-SEC-005

What
SQL query built by inserting values into a string
How it is detected
A line with SELECT … FROM / INSERT INTO / UPDATE … SET / DELETE FROM plus interpolation on the same line: ${} in a template string, + concatenation, an f-string, %, .format(), fmt.Sprintf, a PHP $variable, Ruby #{}. Safe tagged templates (sql…, Prisma.sql…, $queryRaw…) are ignored.
Severity
high
How to verify
Use parameters ($1, ?, :name) or a query builder. If the value is a column name from an allow-list, that is acceptable: check the list.

CR-SEC-006

What
HTML inserted without escaping
How it is detected
dangerouslySetInnerHTML, innerHTML/outerHTML =, insertAdjacentHTML, document.write, v-html, the |safe filter, autoescape off, mark_safe, Markup(), Blade {!! !!}, .html_safe, <%==, {{{ }}}. Clearing with innerHTML = "" is ignored.
Severity
medium
How to verify
Check where the HTML comes from. User data must go through a sanitizer (for example DOMPurify) or be rendered as text.

CR-SEC-007

What
TLS certificate verification disabled
How it is detected
rejectUnauthorized: false, NODE_TLS_REJECT_UNAUTHORIZED=0, verify=False, InsecureSkipVerify: true, CURLOPT_SSL_VERIFYPEER false, ssl._create_unverified_context, strictSSL: false, check_hostname=False, VERIFY_NONE, ServerCertificateValidationCallback => true.
Severity
high
How to verify
If this is local debugging, limit it to the development environment. For a private CA, pass the certificate explicitly (ca, verify=path).

CR-SEC-008

What
CORS: any origin together with credentials
How it is detected
Added lines of one file contain both an any-origin setting (Access-Control-Allow-Origin: *, origin: '*' or true, allow_origins=["*"], AllowAllOrigins, AllowAnyOrigin) and a credentials setting (credentials: true, Allow-Credentials: true, allow_credentials=True).
Severity
high
How to verify
Set an explicit list of trusted origins. Make sure origin: true does not reflect any incoming Origin.

CR-SEC-009

What
JWT read without signature verification
How it is detected
jwt.decode() without jwt.verify() in the same file's added lines (jsonwebtoken), algorithm(s) "none", ignoreExpiration: true, PyJWT decode with verify_signature=False / verify=False, Go ParseUnverified.
Severity
high
How to verify
Use verify with an explicit algorithm list and key; decode only reads a token that was already verified.

CR-SEC-010

What
MD5 or SHA-1 for passwords
How it is detected
An md5/sha1 call (createHash, hashlib, MessageDigest, Digest::MD5, md5()) on a line with a password or secret mentioned nearby (±3 added lines).
Severity
high
How to verify
Use bcrypt, scrypt or Argon2 with a salt for passwords. MD5 for a file checksum is fine — then mark it a false positive.

CR-SEC-011

What
Non-cryptographic random for a token or code
How it is detected
Math.random(), Python random.*, PHP rand()/mt_rand()/uniqid(), Java new Random(), Go math/rand — on a line with token, secret, password, otp, nonce, salt, session, key, code, invite, reset or uuid.
Severity
medium
How to verify
Use crypto.randomUUID()/crypto.getRandomValues(), Python secrets, PHP random_bytes(), Java SecureRandom, Go crypto/rand.

CR-SEC-012

What
Redirect to an address taken from the request
How it is detected
redirect(...) with req.query/params/body, request.args/GET, searchParams.get(), $_GET; location = params.get(...); redirect_to params[...].
Severity
medium
How to verify
Allow only relative paths or allow-listed hosts; check that the target starts with a single “/”, not “//”.

CR-SEC-013

What
Supabase service_role key in client code (pack: Supabase)
How it is detected
service_role / SERVICE_ROLE in a "use client" file (or *.client.tsx), or a NEXT_PUBLIC_/VITE_/REACT_APP_/EXPO_PUBLIC_…SERVICE_ROLE variable in any file.
Severity
critical
How to verify
Keep service_role on the server only (route handler, server action, edge function) without a NEXT_PUBLIC_ prefix. Use the anon key and RLS policies in the client. If the key already shipped in a build, rotate it.

CR-SEC-014

What
RLS disabled or a policy that allows everyone (pack: Supabase / PostgreSQL)
How it is detected
ALTER TABLE … DISABLE ROW LEVEL SECURITY, USING (true), WITH CHECK (true), GRANT ALL … TO anon/public in .sql files and migrations.
Severity
high
How to verify
Check that the table really is public (a reference list, say). Otherwise write a policy conditioned on auth.uid() and role.

CR-SEC-015

What
Firebase rules open data to everyone (pack: Firebase)
How it is detected
allow … : if true; allow read, write; with no condition; test mode if request.time < timestamp.date(…); ".read"/".write": true in the Realtime Database.
Severity
critical
How to verify
Grant access based on request.auth and document ownership; test the rules in the Firebase emulator.

CR-SEC-016

What
Debug mode in a production configuration
How it is detected
DEBUG = True in settings/config, app.run(debug=True), and FLASK_DEBUG/APP_DEBUG/DEBUG=true or debug: true in files with prod/production in the path.
Severity
medium
How to verify
Enable debugging only via a development environment variable and check the value on the production server.

CR-SEC-017

What
A password, token or key is written to the log
How it is detected
A logging call (console.*, logger.*, logging.*, print, fmt.Print*, System.out, puts, error_log) with a variable named like password, secret, token, api_key, authorization, cookie, card, cvv or ssn. Words inside string literals do not count.
Severity
medium
How to verify
Remove the value from the log or mask it; check whether values were already written.

CR-SEC-018

What
Unsafe deserialization
How it is detected
pickle.load(s), yaml.load without SafeLoader, yaml.unsafe_load, Marshal.load, unserialize($_GET/$_POST/…), new ObjectInputStream.
Severity
high
How to verify
Make sure the data only comes from a trusted source; for external data use JSON or yaml.safe_load.

CR-SEC-019

What
777 permissions on files or directories
How it is detected
chmod 777, chmod(…, 0o777), os.chmod(…, 0o777), os.Chmod/MkdirAll/WriteFile with 0777.
Severity
medium
How to verify
Grant the minimum permissions needed (usually 644 for files, 755 for directories) and set the owner.
Security

CR-MIG-001

What
Table or column dropped
How it is detected
DROP TABLE, DROP COLUMN, TRUNCATE TABLE, dropTable/dropColumn, op.drop_table/drop_column, remove_column, drop_table, dropIfExists.
Severity
high
How to verify
Check the backup and rollback plan; drop in two releases: stop using the column first, then drop it. If this is a down migration, mark it a false positive.

CR-MIG-002

What
New NOT NULL column without a default
How it is detected
ADD [COLUMN] … NOT NULL without DEFAULT on the same line; add_column … null: false without default:; op.add_column(… nullable=False) without server_default.
Severity
high
How to verify
Add the column as nullable or with a DEFAULT, backfill, then enforce NOT NULL as a separate step.

CR-MIG-003

What
Column or table renamed
How it is detected
RENAME COLUMN, ALTER TABLE … RENAME TO, RENAME TABLE, renameColumn, rename_column/rename_table, op.alter_column(new_column_name=…), sp_rename.
Severity
medium
How to verify
Find every use of the old name; for zero-downtime rollouts — new column, dual writes, switch, drop the old one.

CR-MIG-004

What
Column type changed
How it is detected
ALTER COLUMN … [SET DATA] TYPE, MODIFY COLUMN, change_column, op.alter_column(type_=…).
Severity
medium
How to verify
Estimate table size and lock time on a data copy; check that every value fits the new type.

CR-MIG-005

What
CREATE INDEX without CONCURRENTLY (PostgreSQL) (pack: PostgreSQL)
How it is detected
CREATE [UNIQUE] INDEX without CONCURRENTLY on a table that is not created in the same file.
Severity
medium
How to verify
For large tables use CREATE INDEX CONCURRENTLY (outside the migration transaction). For small or new tables mark it an accepted risk.

CR-MIG-006

What
An existing migration was edited
How it is detected
A file in a migrations directory (migrations/, db/migrate/, alembic/versions/, prisma/migrations/, supabase/migrations/) is modified rather than added.
Severity
high
How to verify
If the migration was already applied anywhere, revert it and make the change in a new migration.

CR-MIG-007

What
DELETE or UPDATE without WHERE
How it is detected
In .sql — a DELETE FROM / UPDATE … SET statement without WHERE (added lines up to “;”); in code — such a query entirely on one line without WHERE.
Severity
high
How to verify
Make sure changing every row is intended (a backfill, say) and test it on a copy of the data.
Migrations

CR-TST-001

What
Source changed, tests did not
How it is detected
The diff changes code files (not migrations or generated files) but no test file (by path conventions).
Severity
medium
How to verify
Check whether existing tests cover the behaviour; if not, add a test for the changed branch of logic.

CR-TST-002

What
Focused test (.only)
How it is detected
describe/it/test/context.only(…), fit(, fdescribe( in test files.
Severity
high
How to verify
Remove .only; make CI forbid it (for example --forbid-only in Mocha/Playwright, a no-focused-tests lint rule).

CR-TST-003

What
Test disabled (skip)
How it is detected
.skip/.todo, xit/xdescribe/xtest, @pytest.mark.skip/skipif/xfail, @unittest.skip, t.Skip, @Disabled, @Ignore, RSpec skip/pending.
Severity
medium
How to verify
There should be a reason and a ticket to restore the test. If it blocked a green CI, look into why it failed.

CR-TST-004

What
Assertions removed from tests
How it is detected
A test file loses more assertion lines (expect, assert*, should, t.Error/Fatal, require.*, assertThat) than it gains. Removed lines are checked.
Severity
medium
How to verify
Compare removed and new assertions: do the new ones cover the same behaviour?

CR-TST-005

What
Large snapshot update
How it is detected
A snapshot file changes by 200+ lines.
Severity
low
How to verify
Spot-check the snapshot differences; make sure the update is expected from this PR's changes.
Tests

CR-ARC-001

What
New dependencies
How it is detected
New packages in package.json, requirements*.txt, pyproject.toml, Pipfile, go.mod, Cargo.toml, Gemfile, composer.json (in added lines and not in removed ones).
Severity
info
How to verify
Check that the package exists, is maintained, has a clear licence and the exact name (no typos); see whether existing dependencies already cover it.

CR-ARC-002

What
Dependencies changed, lock file did not
How it is detected
Dependencies are added or changed in a manifest, but the matching lock file (package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, go.sum, Cargo.lock, Gemfile.lock, composer.lock…) is not in the diff.
Severity
medium
How to verify
Update the lock file with the same package manager and commit it with the manifest.

CR-ARC-003

What
Server-only module imported into a client component (pack: Next.js App Router)
How it is detected
A "use client" file adds an import of server-only, next/headers, fs, child_process, node:*, @prisma/client, pg, mysql2, mongoose, bcrypt, nodemailer, firebase-admin or stripe.
Severity
high
How to verify
Move the module use into a server component, route handler or server action and pass only data to the client.

CR-ARC-004

What
Non-public environment variable in a client component (pack: Next.js App Router)
How it is detected
process.env.X without the NEXT_PUBLIC_ prefix (except NODE_ENV) in a "use client" file.
Severity
medium
How to verify
If the value is secret, read it on the server. If it is public, rename it with the NEXT_PUBLIC_ prefix.
Architecture

CR-REL-001

What
Exception caught and silently ignored
How it is detected
An empty catch {} (on one line, or catch (…) { followed by “}”), .catch(() => {}), except: pass / except Exception: pass (one or two lines), an empty if err != nil {} in Go.
Severity
medium
How to verify
Handle the error explicitly: log with context, retry, tell the user or rethrow. If ignoring is intended, leave a comment.

CR-REL-002

What
localhost or private IP address in code
How it is detected
http(s)://localhost, 127.0.0.1, 0.0.0.0, [::1], 10.x, 192.168.x, 172.16–31.x in added code lines (tests excluded). Next to process.env/os.environ the confidence is low.
Severity
low
How to verify
Move the address to an environment variable or config and check its value for each environment.
Reliability

CR-MNT-001

What
Very large change in one file
How it is detected
More than 400 added lines in one code file (tests and generated files excluded).
Severity
low
How to verify
Split the change into logical parts or review it section by section; look for duplicates of existing code.

CR-MNT-002

What
TODO / FIXME / HACK added
How it is detected
The words TODO, FIXME, HACK, XXX (upper case) in added code lines.
Severity
info
How to verify
Check that the note does not hide missing logic; file a ticket or finish it before merging.

CR-MNT-003

What
Debug output or breakpoint
How it is detected
console.log/debug/trace/dir, debugger, Python print(, breakpoint(), pdb.set_trace(), var_dump/print_r/dd, binding.pry, puts, System.out.print, printStackTrace, Console.Write — except tests and scripts/, bin/, cli/, tools/ directories.
Severity
low
How to verify
Remove it or replace it with structured logging at a proper level.

CR-MNT-004

What
Type checking or lint suppressed
How it is detected
any / as any, @ts-ignore, @ts-expect-error, @ts-nocheck, eslint-disable, # type: ignore, # noqa, pylint: disable, //nolint, @SuppressWarnings, rubocop:disable, #pragma warning disable. File-wide @ts-nocheck and eslint-disable are medium.
Severity
low
How to verify
See whether the type can be described precisely or the warning's cause fixed; leave a comment explaining why the suppression is needed.

CR-MNT-005

What
Large commented-out code block added
How it is detected
5+ consecutive added comment lines that look like code (; { } ( ) = or return/if/for/const/def/import at the start).
Severity
low
How to verify
Delete the block or explain why it is kept.
Maintainability

Very large file change (CR-MNT-001)

Value
more than 400 added lines

Large snapshot update (CR-TST-005)

Value
200+ changed lines

Commented-out code (CR-MNT-005)

Value
5+ consecutive lines

Findings per rule per file

Value
up to 20, the rest are counted
Thresholds

Test files are detected by path: tests/…, __tests__/…, e2e/…; login.test.ts, cart.spec.js; auth_test.go; test_auth.py, auth_test.py; AuthServiceTest.java; AuthTests.cs; user_spec.rb; UserTest.php; LoginTests.swift; __snapshots__/x.snap.

Limitations

  • The code is not executed; diff lines are matched against patterns. Patterns can miss a problem (for example SQL built over several lines) or fire falsely.
  • Cross-file relations, types and data flow are not analysed: a rule sees a line, not the program. Files outside the diff are not considered.
  • This does not replace SAST, tests or an engineering review — it is a fast first pass with evidence that helps you not miss common mistakes.

Privacy

  • The diff is parsed in your browser: the code is not sent to a server or put into the page address.
  • The draft, decisions and versions are stored only in this browser (localStorage); “Clear all” deletes them.
  • Values that look like secrets are replaced with [REDACTED] in evidence and exports; a warning is shown before export.
  • Analytics receives only the fact of a review or an export and a category (highest severity, file format) — no code or paths.
  • The result reaches us only if you send a request yourself and keep the “Attach the result” box ticked — the form shows exactly what will be sent. The summary holds counts and rule · file:line · title, never code.

Related tools

All tools · 40
Tell us about your task — we'll review your request and get back to you

Need a review of code written with AI agents?

A code audit: access and roles, secrets, database and RLS, APIs, tests and deployment — with a risk map and a fix plan. The first short call is free; scope and cost come after a brief.

  • The first short conversation is free — we choose the format
  • NDA — yours or ours
  • Pricing after a brief and an agreed scope

Please do not send passwords, access keys or source code through this form — we will agree a safe way to share access separately.

By clicking the button you agree to the processing of your personal data.