Back to Blog
critical SEVERITY7 min read

How buffer overflow in strcpy() happens in C configuration parsing and how to fix it

A critical buffer overflow vulnerability in `src/rpconfig.h` allowed attackers to corrupt memory by providing configuration values exceeding buffer size limits. The `rpcSetText()` function used `strcpy()` to copy user-controlled data into a fixed 256-byte buffer without bounds checking, enabling stack corruption and potential code execution. Replacing `strcpy()` with `strncpy()` and enforcing a 255-byte limit eliminated the overflow risk.

O
By Orbis AppSec
Published July 4, 2026Reviewed July 4, 2026

Answer Summary

This is a CWE-120 buffer overflow vulnerability in C's `rpconfig.h` file, specifically in the `rpcSetText()` function at line 482. The function used `strcpy()` to copy user-controlled configuration text into a fixed 256-byte buffer without validating input length. An attacker could provide malicious configuration files with values exceeding 256 bytes to overflow the stack, corrupt adjacent memory, and potentially execute arbitrary code. The fix replaced `strcpy(config.entries[i].text, text)` with `strncpy(config.entries[i].text, text, 255)` to enforce bounds checking and prevent buffer overruns.

Vulnerability at a Glance

cweCWE-120 (Buffer Copy without Checking Size of Input)
fixReplace strcpy() with strncpy() limiting copy to 255 bytes
riskMemory corruption, arbitrary code execution via malicious configuration files
languageC
root causestrcpy() copies unbounded user input into fixed 256-byte buffer
vulnerabilityBuffer overflow via unchecked strcpy() in configuration parsing

Introduction

In the rpconfig.h file of this C codebase, we discovered a critical buffer overflow vulnerability at line 482 within the rpcSetText() function. This function handles configuration text entries, copying user-provided values into fixed-size buffers using the notoriously unsafe strcpy() function. Without any bounds checking, an attacker could supply a malicious configuration file with text values exceeding the 256-byte buffer limit, triggering a stack-based buffer overflow that corrupts adjacent memory and potentially enables arbitrary code execution.

This vulnerability exemplifies why strcpy() has been considered dangerous for decades—it blindly copies data until it encounters a null terminator, regardless of destination buffer size. The rpcSetText() function processes configuration keys and their associated text values, making it a prime target for exploitation through crafted configuration files. With the buffer allocated on the stack and no length validation, this represents a textbook case of CWE-120: Buffer Copy without Checking Size of Input.

The Vulnerability Explained

The vulnerable code in src/rpconfig.h at line 482 looks like this:

int rpcSetText(rpcProjectConfig config, const char *key, const char *text)
{
    // ... earlier code ...

    if (TextIsEqual(config.entries[i].key, key) &&
        !TextIsEqual(config.entries[i].text, text))
    {
        memset(config.entries[i].text, 0, 256);
        strcpy(config.entries[i].text, text);  // VULNERABLE LINE
        result = i;
        break;
    }
}

The problem is crystal clear: config.entries[i].text is a fixed 256-byte buffer (as evidenced by the memset() call on the previous line), but strcpy() copies the entire text parameter without checking its length. If text contains more than 255 characters (256 minus the null terminator), strcpy() will write beyond the buffer boundary, overwriting whatever memory comes next on the stack.

How the Exploitation Works:

An attacker could craft a malicious configuration file with a text value exceeding 256 bytes:

[Section]
key1 = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...
       [continues for 300+ characters]

When rpcSetText() processes this entry, here's what happens:

  1. The function finds the matching key in config.entries[i]
  2. It clears the 256-byte text buffer with memset()
  3. It calls strcpy() to copy the 300+ character string
  4. strcpy() writes 256 bytes into the buffer, then continues writing the remaining 44+ bytes into adjacent stack memory
  5. This overwrites local variables, saved frame pointers, or even the return address
  6. If the attacker controls the overwritten data precisely, they can redirect program execution

Real-World Impact:

This vulnerability affects production code that parses configuration files. The consequences include:

  • Memory corruption: Overwriting adjacent stack variables leads to unpredictable program behavior and crashes
  • Information disclosure: Corrupted pointers might leak sensitive memory contents
  • Arbitrary code execution: By carefully crafting the overflow payload, an attacker could overwrite the return address to hijack control flow
  • Privilege escalation: If this code runs with elevated privileges, successful exploitation could grant system-level access

The PR notes that line 515 in the same file uses a similar pattern, suggesting this vulnerability might exist in multiple locations within the configuration parsing logic.

The Fix

The fix is elegant and effective—replacing the unsafe strcpy() with strncpy() and enforcing a maximum copy length:

Before (Vulnerable):

memset(config.entries[i].text, 0, 256);
strcpy(config.entries[i].text, text);

After (Secure):

memset(config.entries[i].text, 0, 256);
strncpy(config.entries[i].text, text, 255);

Why This Works:

The change from strcpy() to strncpy() with a limit of 255 bytes provides multiple layers of protection:

  1. Bounds enforcement: strncpy() will never write more than 255 bytes into the destination buffer, preventing overflow
  2. Null terminator space: Limiting to 255 bytes leaves room for the null terminator in the 256-byte buffer
  3. Predictable behavior: Even with malicious input exceeding 255 characters, the function safely truncates the string

The fix specifically uses 255 (not 256) as the length parameter because:
- The buffer is 256 bytes total
- We need to reserve one byte for the null terminator
- strncpy() doesn't automatically add a null terminator if the source is longer than the limit
- The prior memset() call ensures the buffer is zero-initialized, providing null termination

Important Note on strncpy() Behavior:

While this fix is secure, developers should understand that strncpy() has quirky behavior:
- If the source string is shorter than the limit, strncpy() pads the remaining space with null bytes
- If the source string is longer than the limit, strncpy() does NOT add a null terminator
- In this case, the memset() call beforehand ensures null termination, making the fix safe

Additional Protection:

The PR also includes a comprehensive regression test that validates the buffer length invariant with various payload sizes, including boundary conditions and extreme overflow attempts. This test ensures future code changes won't reintroduce the vulnerability.

Prevention & Best Practices

1. Avoid Unsafe String Functions

Never use these functions in production code:
- strcpy() → Use strncpy(), strlcpy(), or snprintf()
- strcat() → Use strncat() or strlcat()
- sprintf() → Use snprintf()
- gets() → Use fgets()

2. Always Validate Input Length

Before copying any user-controlled data:

if (strlen(text) >= sizeof(config.entries[i].text)) {
    // Handle error: input too long
    return ERROR_INPUT_TOO_LONG;
}
strncpy(config.entries[i].text, text, sizeof(config.entries[i].text) - 1);
config.entries[i].text[sizeof(config.entries[i].text) - 1] = '\0';

3. Use Safer Alternatives

Consider modern C string handling approaches:

// Option 1: snprintf() for guaranteed null termination
snprintf(config.entries[i].text, sizeof(config.entries[i].text), "%s", text);

// Option 2: strlcpy() if available (BSD systems)
strlcpy(config.entries[i].text, text, sizeof(config.entries[i].text));

4. Enable Compiler Protections

Modern compilers offer runtime protections:
- Stack canaries (-fstack-protector-strong)
- Address Space Layout Randomization (ASLR)
- Data Execution Prevention (DEP/NX)
- Fortify Source (-D_FORTIFY_SOURCE=2)

5. Static Analysis Integration

Integrate tools that detect unsafe string operations:
- Semgrep: Rules like dangerous-strcpy flag these patterns
- Clang Static Analyzer: Detects buffer overflows at compile time
- Coverity: Commercial tool with deep buffer overflow detection
- Flawfinder: Scans C/C++ code for security weaknesses

6. Follow CERT C Secure Coding Standards

The CERT C standard STR07-C explicitly states: "Use the bounds-checking interfaces for string manipulation." This vulnerability violates that guideline.

7. Security Code Review Checklist

When reviewing C code, always check:
- Are buffer sizes explicitly defined and documented?
- Is every string copy operation bounded?
- Are null terminators guaranteed?
- Could any input source provide oversized data?

Key Takeaways

  • Never use strcpy() in rpcSetText() or similar configuration parsing functions: The combination of fixed 256-byte buffers and unbounded string copying creates exploitable buffer overflows
  • The memset(config.entries[i].text, 0, 256) pattern requires strncpy(..., 255) not 256: Always leave one byte for null termination when copying into pre-zeroed buffers
  • Configuration file parsers are high-value attack targets: Functions like rpcSetText() that process external configuration data must validate all input lengths before copying
  • Line 515 in rpconfig.h needs similar review: The PR notes another potential vulnerability using the same pattern, highlighting how buffer overflow issues often cluster in related code
  • Regression tests should include boundary conditions: The test suite now validates buffer limits with exact-boundary (100 chars), boundary+1 (101 chars), and extreme overflow (1000+ chars) payloads

How Orbis AppSec Detected This

Source: User-controlled configuration file text values passed to rpcSetText() function via the text parameter

Sink: strcpy(config.entries[i].text, text) call at src/rpconfig.h:482 that copies unbounded input into a fixed 256-byte stack buffer

Missing control: No length validation or bounds checking before the strcpy() operation, allowing input exceeding 255 characters to overflow the buffer

CWE: CWE-120 (Buffer Copy without Checking Size of Input)

Fix: Replaced strcpy() with strncpy() using a 255-byte limit to enforce bounds checking and prevent buffer overflow

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

This buffer overflow in rpcSetText() demonstrates why legacy C string functions remain one of the most persistent security vulnerabilities in software. A single line using strcpy() instead of strncpy() created a critical security flaw that could enable memory corruption and arbitrary code execution through malicious configuration files. The fix was straightforward—enforcing a 255-byte copy limit—but the lesson is profound: in C programming, every string operation requires explicit bounds checking.

For developers working with C codebases, especially those handling external input like configuration files, this vulnerability serves as a reminder to audit all string manipulation code. Replace unsafe functions, validate input lengths, enable compiler protections, and integrate static analysis tools into your development pipeline. The cost of prevention is minimal compared to the potential impact of exploitation.

References

Frequently Asked Questions

What is a buffer overflow in strcpy()?

A buffer overflow in strcpy() occurs when the function copies a string larger than the destination buffer can hold, overwriting adjacent memory. Unlike strncpy(), strcpy() has no size limit and continues copying until it finds a null terminator, making it dangerous with user-controlled input.

How do you prevent buffer overflow in C?

Use bounded string functions like strncpy(), snprintf(), or strlcpy() that accept a maximum size parameter. Always validate input length before copying, allocate buffers with adequate size plus null terminator, and enable compiler protections like stack canaries and ASLR.

What CWE is buffer overflow?

Buffer overflow is classified as CWE-120 (Buffer Copy without Checking Size of Input) when caused by unchecked copying functions. Related CWEs include CWE-119 (Improper Restriction of Operations within Memory Buffer) and CWE-787 (Out-of-bounds Write).

Is using strncpy() enough to prevent buffer overflow?

strncpy() prevents buffer overflow but doesn't guarantee null termination if the source exceeds the specified length. Always set the last byte to '\0' manually or use n-1 as the length parameter. Consider safer alternatives like strlcpy() or snprintf() for complete protection.

Can static analysis detect buffer overflow?

Yes, modern static analysis tools can detect many buffer overflow patterns by tracking buffer sizes and identifying unsafe functions like strcpy(), gets(), and sprintf(). Tools like Semgrep, CodeQL, and Coverity can flag these issues, though some complex overflows require dynamic analysis or fuzzing.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #1

Related Articles

high

How buffer overflow via sprintf() happens in C string formatting and how to fix it

A high-severity buffer overflow vulnerability was discovered in `bench/strbuild/strbuild.c` where `sprintf()` wrote formatted output into a 64-byte stack buffer (`line[64]`) without any bounds checking. An attacker who could influence the values in the `NAMES[]`, `c[]`, or `v[]` arrays could overflow this buffer, potentially corrupting the stack and hijacking control flow. The fix replaces `sprintf()` with `snprintf(line, sizeof(line), ...)` to enforce a strict 64-byte write limit.

critical

How buffer overflow happens in C tar header parsing and how to fix it

A critical buffer overflow vulnerability was discovered in `microtar/microtar.c` where the `raw_to_header()` and `header_to_raw()` functions used unbounded `strcpy()` and `sprintf()` calls to copy tar header fields. Malicious tar files with non-null-terminated name fields could overflow destination buffers, potentially leading to code execution. The fix replaces all unsafe string operations with bounded alternatives: `memcpy()` with explicit null-termination and `snprintf()` instead of `sprintf(

critical

How buffer overflow happens in C ieee80211_input() and how to fix it

A critical buffer overflow vulnerability was discovered in `src/firmware/src/net/ieee80211.c` at line 1584, where the `ieee80211_input()` function processed raw 802.11 data frames without verifying that the incoming frame was large enough to contain a valid `ieee80211_frame` header. An attacker within wireless range could craft undersized or malformed frames to trigger memory corruption, potentially leading to remote code execution on the firmware. The fix adds a single, targeted bounds check th

high

How buffer overflow from unsafe string copy functions happens in C network interface code and how to fix it

A high-severity buffer overflow vulnerability was discovered in `generic/eth-impl.c`, where unsafe `strncpy()` and `sprintf()` calls could write beyond buffer boundaries when handling network interface names and device filenames. The fix replaced these dangerous functions with bounded `snprintf()` calls that guarantee null-termination and prevent memory corruption.

critical

How buffer overflow in FuzzIxml.c sprintf() happens in C and how to fix it

A critical buffer overflow vulnerability was discovered in `fuzzer/FuzzIxml.c` where `sprintf()` wrote a PID-formatted filename into a fixed 256-byte stack buffer without any bounds checking. The fix replaces `sprintf()` with `snprintf()`, explicitly passing the buffer size to prevent any overflow. While exploitation in this specific fuzzer context requires local access, the pattern is a textbook example of CWE-120 that developers should recognize and eliminate everywhere it appears.

critical

How buffer overflow happens in C HTML parsing and how to fix it

A critical buffer overflow vulnerability in `include/html_parse.h` allowed attackers to overflow buffers by providing malicious HTML input exceeding buffer capacity. The fix adds proper bounds checking before memcpy() operations to prevent memory corruption and potential code execution.