CWE-415 in APIs
- CWE ID
- CWE-415
- Category
- Input Validation
- Severity
- CRITICAL
- Short Name
- Double Free
What is Cwe 415?
Cwe 415: Double Free occurs when a program attempts to free the same memory location twice. This weakness can lead to memory corruption, crashes, or even exploitable conditions where an attacker can execute arbitrary code.
The weakness typically manifests when:
- A pointer to allocated memory is freed, then the pointer is reused or re-freed
- Multiple code paths free the same resource without proper state tracking
- Error handling paths free resources that were already freed in the normal execution path
Double free vulnerabilities are particularly dangerous because they can corrupt the heap allocator's internal data structures, potentially allowing an attacker to overwrite function pointers or control program flow.
Remediation
Fixing Cwe 415 requires careful resource management and defensive programming:
1. Use RAII/Smart Pointers (C++/Rust)
// C++ - use smart pointers to prevent double free
std::unique_ptr<Resource> resource = std::make_unique<Resource>();
// No need to manually free - unique_ptr handles it
2. Nullify Pointers After Free
void cleanup(Resource* res) {
if (res != NULL) {
free(res);
res = NULL; // Prevent reuse
}
}
3. Use Reference Counting
# Python - use context managers
class Resource:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.cleanup()
# Only cleaned up once when exiting context
with Resource() as res:
process(res)
# Automatically cleaned up here, even if process() raises
4. Implement Safe Cleanup Patterns
// Node.js - safe cleanup with flags
function processRequest(data) {
let cleanedUp = false;
try {
const result = processData(data);
return result;
} catch (error) {
throw error;
} finally {
if (!cleanedUp) {
cleanup(data);
cleanedUp = true;
}
}
}
5. Use Modern Frameworks with Built-in Safety
Modern web frameworks handle resource management automatically:
// Express.js - let the framework handle cleanup
app.post('/api/data', async (req, res) => {
try {
const result = await processData(req.body);
res.json(result);
} catch (error) {
res.status(500).json({error: 'Processing failed'});
}
// No manual cleanup needed - Express handles response cleanup
});
6. Implement Comprehensive Error Handling
// Go - use defer for guaranteed cleanup
def processRequest(w http.ResponseWriter, r *http.Request) {
db, err := dbPool.Get()
if err != nil {
http.Error(w, "DB error", 500)
return
}
defer db.Close() // Guaranteed to run once
// Process request
result, err := processData(db, r.Body)
if err != nil {
http.Error(w, err.Error(), 400)
return
}
json.NewEncoder(w).Encode(result)
}
The key principle is ensuring resources are freed exactly once, regardless of which code path is taken. Using modern language features, framework abstractions, and defensive programming patterns eliminates most double free vulnerabilities.