
Prompt Engineering for Security: Writing Safer AI Code Requests
Why safer AI code requests matter
I use AI code assistants for small scaffolding jobs all the time, but prompts that touch security need a different shape. If you ask for “a quick endpoint” or “a script that makes this work,” the model will usually optimize for completion, not for boundary checks, error handling, or abuse resistance.
That is fine for a throwaway prototype. It is a bad default for anything that handles auth, files, payments, tokens, or user-generated content.
The real issue is not that the model is malicious. The issue is that vague prompts hide the rules that matter. If you do not spell out the trust boundary, the assistant fills the gap with assumptions.
The failure mode: vague prompts produce risky code
A weak prompt often looks like this:
“Write a Node.js route that lets users upload a profile image and store it.”
That sounds normal, but it leaves out the parts that make the code safe:
- who is allowed to upload
- what file types are acceptable
- where the file is stored
- whether the filename is trusted
- how size limits are enforced
- whether the upload is public or private
What AI models often miss in security-sensitive tasks
In practice, I keep seeing the same misses:
- authorization checks get implied instead of implemented
- validation happens on the client, not the server
- error paths leak internal details
- secrets end up in logs or examples
- dependency choices are made without threat context
- dangerous defaults sneak in, like permissive CORS or weak regex validation
The model may generate code that works, but “works” is not the same as “safe under abuse.”
A safer prompt pattern for code generation
The safest prompts are specific about the boundary, the allowed inputs, and the failure behavior.
State the trust boundary first
Start with who is trusted and who is not.
For example:
- authenticated user
- free account vs paid account
- internal admin tool vs public web app
- server-side data vs untrusted request data
If you do not define the trust boundary, the model may treat user input as if it were already approved.
Define allowed data, not just desired behavior
Do not only say what you want the code to do. Say what it may accept.
Good prompt details include:
- accepted file types
- maximum request size
- allowed characters in identifiers
- safe output format
- which fields are read-only
- which data must never be exposed
That gives the assistant concrete guardrails instead of a vague goal.
Ask for validation, logging, and failure handling
A security-safe request should ask for all three:
- validation: reject bad input early
- logging: record important security events without leaking secrets
- failure handling: fail closed, not open
If you omit those, many generated examples will quietly assume happy-path behavior.
Example: rewriting a risky request into a safer one
Unsafe prompt example
“Write a JavaScript endpoint that accepts a URL and fetches the page title.”
That sounds harmless, but it can lead to SSRF, internal network access, or metadata leaks if the server fetches arbitrary URLs.
Safer prompt example
“Write a Node.js endpoint that accepts a URL from an authenticated user and returns the page title only. Reject private IP ranges, localhost, non-HTTP(S) schemes, and redirects to disallowed hosts. Limit requests to 2 seconds, cap response size, and return a generic error message. Log validation failures without storing the full URL.”
That version changes the output. It tells the model where the risk is and what to defend against.
What to review in the generated code
Even a good prompt does not remove review. I still check the same three areas first.
Authorization checks
Look for the actual decision point:
- is the user authenticated?
- is this resource owned by them?
- is there a server-side role check?
- is access decided before the action happens?
If the code only checks a UI flag or a request parameter, that is not authorization.
Input validation and output encoding
Check that the code validates on the server and encodes on output:
- strict schema validation
- type checks on every field
- length limits
- allowlists instead of broad regexes where possible
- HTML, JSON, or command output encoded for the target sink
A lot of AI-generated code looks clean until you trace where untrusted data lands.
Secrets handling and dependency risk
I also scan for these mistakes:
- API keys printed in logs
- secrets embedded in examples
- debug output that includes tokens
- unnecessary packages with large attack surfaces
- helpers that shell out to system commands without a strong reason
If the assistant adds a dependency, I ask whether the same task can be done with built-in APIs first.
Testing the result before you trust it
Build a minimal repro
Do not review the code only by reading it. Run the smallest possible test that exercises the risky path.
For example:
- send malformed input
- try empty strings and oversized payloads
- use a different user account
- remove one required field
- simulate a failed downstream service
A minimal repro usually shows whether the code fails closed or just fails loudly.
Check edge cases and abuse cases
I like to test in this order:
- normal input
- missing input
- malformed input
- boundary-length input
- unauthorized input
- replayed input
- poisoned or unexpected content
That sequence catches the “looks fine in the demo” problem fast.
If a prompt asks for code that touches auth, files, URLs, or tokens, make the assistant state its assumptions before it writes code.
A prompt checklist for developers
Use this before you ask for security-sensitive code:
| Check | Ask yourself |
|---|---|
| Trust boundary | Who is allowed to call this, and who is not? |
| Input scope | What data is allowed, and what must be rejected? |
| Failure mode | Does the code fail closed on bad input? |
| Output safety | Could the result leak secrets or unsafe content? |
| Logging | Are security events logged without exposing sensitive values? |
| Dependencies | Is this using the simplest safe library or API? |
| Tests | Have I tried malformed, unauthorized, and oversized inputs? |
Conclusion
The safest AI code requests are boring on purpose. They name the trust boundary, restrict the input, and demand validation and failure handling up front.
That does not guarantee perfect code. It does make the first draft much harder to abuse.
My rule is simple: if I would not hand the prompt to a junior developer without extra context, I do not hand it to the model either.


