The listing used to sell CVE coverage. There is no CVE feed on this page. A code vulnerability scanner here means four string checks against whatever you pasted, labelled Critical, High, or Medium, with a one-line rewrite under each ticket. Treat a hit as a line to read. Treat a miss as silence.
The engine searches text.
No parser. No taint graph. A query built from two constants next to SELECT still lights up. A request value that travels through three helpers before reaching innerHTML does not. I have watched teams file both kinds of ticket with equal urgency. Only one of those tickets belonged in the sprint.
If you want a wider JavaScript-leaning ruleset with line numbers on more sinks, open the Code Security Scanner after this pass. The two pages share a family of bugs. They do not share a ruleset, a layout, or a rating widget.
Four strings. That is the whole engine.
Each family has one trigger. Match, and a ticket prints. Fail to match, and the family stays quiet even when the bug sits in the file.
| Family | Severity | What has to appear | What slips past |
|---|---|---|---|
| SQL injection, CWE-89 | Critical | SELECT plus concatenation (+, PHP ., Python % or .format) | Query builders, ORM where clauses, SQL sitting in another module |
| XSS, CWE-79 | High | innerHTML with no sanitizer named in the file, or a language-specific echo of request input | A helper that writes the DOM, React dangerouslySetInnerHTML, Vue v-html |
| Weak hashing, CWE-328 | Medium | md5, sha1, hashlib.md5, MessageDigest MD5 or SHA-1, MD5.Create | bcrypt used with a round count of 4, a fast hash used on purpose as a file checksum |
| Hardcoded password, CWE-798 | High | An assignment matching password = "…" | api_key, token, secrets in YAML, an .env file you did not paste |
CWE numbers on the tickets are labels, not lookups. Nothing here queries MITRE. If a ticket cites CWE-89, read the concatenated query. Do not search a CVE database for a match that was never made.
What the chips change
Two jobs. They pick the dirty sample. They add a few extra needles for that language.
They do not load a PHP parser or a C# compiler. A Java file still gets the SELECT-plus-+ check because the characters look the same. Browser-only needles stay quiet outside JavaScript. That is the entire trick.
| Chip | Extra needles | Still silent on |
|---|---|---|
| JavaScript | innerHTML without sanitize or DOMPurify in the same paste | JSX, template literals assigned through a wrapper |
| Python | hashlib.md5, hashlib.sha1, mark_safe, Markup(, percent-formatted SQL | sqlalchemy.text, Jinja autoescape left on |
| Java | MessageDigest.getInstance("MD5") or "SHA-1", print of getParameter | A PreparedStatement used correctly, JSP EL in another file |
| PHP | echo $_GET / $_POST, mysql_query with . concatenation | htmlspecialchars used, PDO placeholders |
| C# | Html.Raw, MD5.Create, SHA1.Create | Parameterized SqlCommand, Razor encoding |
| SQL | EXEC( of a concatenated string, HASHBYTES('MD5' | Parameterized sp_executesql with a typed parameter list |
Pick the chip that matches the paste so the extra needles have a chance. Leave JavaScript selected on a PHP file and you still get SELECT concatenation and password =, while echo $_GET stays dark.
Load a dirty sample, then read the tickets
The JavaScript sample is a short lie a junior review would ship.
const password = "toolexe-local-dev";const q = "SELECT * FROM accounts WHERE email='" + email + "'";box.innerHTML = "<p>" + email + "</p>";const digest = md5(password);Four tickets. The password line is High because git keeps deleted secrets. Rotate the value after you move it. The SELECT line is Critical because a quote in email becomes syntax. The innerHTML line is High because a payload in email becomes markup. The md5 line is Medium because a fast hash on a password is a lookup table, not storage.
Python, Java, PHP, and C# samples trip the same four families with the idioms those files use. The SQL sample has no markup sink, so XSS stays quiet and you get three tickets. Load one, run the checks, then replace the sample with the file on your desk.
Paste the file sitting in your review tab. Skip the demo if you already believe the four families exist.
Clean output is the result I trust least
A twelve-line tutorial misses all four families. A four-hundred-line controller that sanitizes inside a shared helper misses them too. The second file is the one that ships.
Common ways a real bug stays dark:
- The sink lives in a partial. You pasted the controller.
- The query goes through an ORM. There is no
SELECTliteral to match. - The password is named
dbPassor read fromprocess.env. The assignment pattern never fires. - Hashing goes through a wrapper named
legacyDigest. The lettersmd5never appear. - XSS is
el.innerHTML = tpl(user)afterinnerHTMLwas aliased. The identifier changed. The sink did not.
A file that comes back clean has not been proven safe.
Long functions hide sinks well. When a paste comes back quiet and the function still feels crowded, run the Code Complexity Analyzer on the same buffer and read the hotspots slowly. For a concatenated query you intend to keep, rewrite it next to the SQL Query Tester so the parameterized form still returns the rows you expect.
Skip this page when
Some jobs do not belong here. Send them somewhere else instead of stretching four string checks until they pretend to be a program.
- You need CVE matching against a lockfile. This page never reads
package-lock.json,composer.lock, or a container image. - You need a whole-repository walk. The textarea holds one paste. CI belongs to a SAST job with a parser.
- You need taint. Request input that reaches a sink through helpers is out of scope.
- You need a merge gate. A Medium ticket on
md5used as a checksum will fail builds you did not mean to fail.
When the goal is a failing test rather than a list of strings, use the Security Test Generator. Point it at https://api.toolexe.com as a placeholder, then swap the routes for yours before the file hits CI.
The rewrite for each ticket, without the one-liner
The report prints one sentence of advice. Here is what each sentence is asking you to do.
Stop assembling SQL with string operators
Placeholders keep the query shape on one channel and the data on another. A quote in a username stops being syntax. Escaping helpers try to solve the same problem by rewriting the data, and they lose to encoding edge cases. PDO, psycopg, prepared SqlCommand, and ? placeholders in node drivers all do the same split.
// flagged
const q = "SELECT * FROM accounts WHERE email='" + email + "'";const q = "SELECT * FROM accounts WHERE email = ?";db.query(q, [email]);Write a text node, or build elements
textContent writes characters. A <script> tag inside the value stays visible as text. When you need real markup, create nodes with createElement or run a maintained sanitizer before assignment. In PHP, htmlspecialchars on output. In Razor, keep Html.Raw off the request path. Django templates already escape. mark_safe is the way back out.
// flagged
box.innerHTML = "<p>" + email + "</p>";const p = document.createElement("p");p.textContent = email;box.replaceChildren(p);Stop hashing passwords with MD5 or SHA-1
A password needs a slow, salted KDF: Argon2id, scrypt, or bcrypt with a work factor your hardware still feels. MD5 and SHA-1 are fast. Fast is the opposite of what you want when the input is a human-chosen secret. File checksums are a different job. If the ticket fired because you hashed a download, leave the checksum, rename the wrapper so the letters md5 are not sitting next to the word password, and move on.
If you are staring at two hex strings and trying to remember why SHA-1 is the wrong primitive for a password, the SHA-1 Hash Generator and the MD5 Hash Generator show the digest. They do not store a password. Neither should this page.
Get the literal out of the file, then rotate
Moving password = "toolexe-local-dev" into .env and adding the file to .gitignore is half the work. The value has lived in git since the first push. Rotate it. Client bundles are a special case: anything shipped to the browser is public, so a key that reaches the bundle needs origin restrictions on the provider dashboard, not hiding.
Next to the Code Security Scanner, not instead of it
I keep both pages because the false-positive shapes differ. This desk fires four families and stops. The Code Security Scanner walks a longer JavaScript-shaped list, including eval, document.write, localStorage next to a token, and a noisy CSRF rule on fetch. Cross-checking the same paste on both pages is useful. Treating either page as a release gate is not.
Use this desk first on a file you already have open. Twelve seconds tells you whether a concatenated query or a leftover password is sitting in the buffer. Then read the file. The tickets are a pointer, not a substitute for that read.
Rules reviewed against the four families shipping in this pagewise script. Scanning runs in your browser. Toolexe does not upload, store, or log the paste.
