| name | sharp-edges |
| description | Identify dangerous API footguns, surprising default behaviors, and sharp edges in codebases and dependencies. Adapted from Trail of Bits. Use during code review to catch APIs that are easy to misuse, configurations that surprise, and abstractions that leak. |
Sharp Edges Detection
Sharp edges are APIs, configurations, and patterns that are easy to use incorrectly. They work in the happy path but break in subtle, dangerous ways.
Three Adversary Types
When evaluating sharp edges, consider three types of users:
1. The Naive Developer
- Uses the API without reading docs carefully
- Copies examples from Stack Overflow
- Assumes defaults are safe
- Question: "Will this API hurt someone who doesn't know its quirks?"
2. The Malicious User
- Intentionally sends unexpected input
- Exploits race conditions and edge cases
- Chains small issues into big exploits
- Question: "Can someone deliberately trigger the bad behavior?"
3. The Future Maintainer
- Modifies code without full context
- Refactors without understanding invariants
- Doesn't know why something was done a certain way
- Question: "Will a reasonable change to this code introduce a bug?"
Sharp Edge Categories
1. Surprising Default Behavior
APIs whose defaults do something unexpected:
parseInt("08")
parseInt("08", 10)
[10, 2, 1].sort()
[10, 2, 1].sort((a, b) => a - b)
JSON.parse('{"a": {"b": 1}}', (key, val) => {
})
const res = await fetch('/api')
if (!res.ok) throw new Error(`HTTP ${res.status}`)
2. Silent Failures
Operations that fail without telling you:
const obj = Object.freeze({ nested: { value: 1 } })
obj.nested.value = 2
const map = new Map()
map.set(1, 'number')
map.set('1', 'string')
map.get(1)
const obj = {}
obj[1] = 'number'
obj['1'] = 'string'
obj[1]
Promise.all([p1, p2, p3])
Promise.allSettled([p1, p2, p3])
3. Type Coercion Traps
null == undefined
0 == ''
false == '0'
typeof null
NaN === NaN
Number.isNaN(x)
4. Concurrency Sharp Edges
[1, 2, 3].forEach(async (item) => {
await processItem(item)
})
for (const item of [1, 2, 3]) {
await processItem(item)
}
const exists = await db.findOne({ email })
if (!exists) {
await db.create({ email })
}
5. Security Sharp Edges
new URL('http://evil.com\\@good.com')
/admin/.test('not-admin-page')
if (userToken === storedToken) { }
path.join('/uploads', userInput)
path.resolve('/uploads', userInput)
6. Database Sharp Edges
db.users.find({ username: req.body.username })
db.query(`SELECT * FROM users WHERE name LIKE '%${input}%'`)
const users = await User.findAll()
for (const user of users) {
const posts = await user.getPosts()
}
7. Framework Sharp Edges
useEffect(() => {
let cancelled = false
fetchData().then(data => {
if (!cancelled) setState(data)
})
return () => { cancelled = true }
}, [])
app.use(cors())
app.use(helmet())
app.use(authMiddleware)
app.use(rateLimiter)
Detection Checklist
For each API/function/config in review:
[ ] What happens with empty/null/undefined input?
[ ] What happens with extremely large input?
[ ] What happens with concurrent access?
[ ] What happens when the network is slow/down?
[ ] What are the default values? Are they safe?
[ ] Does it fail silently or loudly?
[ ] Is the error message helpful or misleading?
[ ] Will a future developer understand the constraints?
[ ] Is there a safer alternative API?
Documentation Pattern
When you find a sharp edge, document it:
SHARP EDGE: [API/pattern name]
SURPRISE: [What happens that developers don't expect]
DANGER: [What can go wrong -- security, data loss, correctness]
FIX: [The safe alternative]
AFFECTED: [Which files/modules in this codebase use it]
Integration with vibecosystem
- code-reviewer agent: Check for known sharp edges during review
- security-reviewer agent: Focus on security sharp edges
- self-learner agent: When a sharp edge causes a bug, learn and add to detection
- tdd-guide agent: Write tests that exercise sharp edge behavior
Inspired by Trail of Bits sharp-edges plugin.