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

critical

How integer overflow in buffer size calculations happens in C and how to fix it

A critical integer overflow vulnerability was discovered in `src/api.c`'s `find_config_path()` function, where string lengths were added together without overflow checks before allocating a buffer. An attacker controlling environment variables like `APPDATA`, `HOME`, or `XDG_DATA_HOME` could supply extremely long values to trigger an integer overflow, resulting in an undersized buffer allocation and a subsequent heap buffer overflow. The fix adds explicit overflow guards using `SIZE_MAX` compari

critical

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

A classic buffer overflow vulnerability was discovered in `bld/pbide/dlldbg/dlldbg.c` at line 80, where an unbounded `sprintf()` call wrote a user-influenced `dllName` string into a fixed-size `fmtBuffer` without any length checking. An attacker supplying a maliciously crafted DLL name could overflow the buffer, overwrite adjacent memory, and potentially achieve arbitrary code execution. The fix replaces `sprintf()` with `snprintf()`, passing `sizeof(fmtBuffer)` as an explicit bound to ensure th

critical

How buffer overflow in strcpy() happens in C bin2coff tool and how to fix it

A critical buffer overflow vulnerability was discovered in `tools/bin2coff.c` where multiple `strcpy()` operations copied user-controlled label strings into fixed-size buffers without bounds checking. An attacker could provide maliciously long labels to overflow destination buffers and corrupt adjacent memory structures, potentially leading to arbitrary code execution. The fix replaced unsafe string operations with bounded alternatives like `strlcpy()` and `snprintf()`.

critical

How buffer overflow in handle_interlink_event() happens in C terminal event handling and how to fix it

A critical buffer overflow vulnerability was discovered in `src/terminal/event.c` at line 250, where `memcpy()` blindly copied `info->cwd` into a fixed-size `term->cwd` buffer without verifying the source string's actual length. An attacker who could supply a crafted working directory path longer than `MAX_CWD_LEN` could corrupt adjacent heap memory, potentially leading to code execution. The fix replaces the unsafe `memcpy()` call with `safe_strncpy()`, which enforces the destination buffer bou

high

How buffer overflow happens in C string operations with strcpy/strncpy and how to fix it

A critical buffer overflow vulnerability in `src/pomoc.c` was discovered where `strncpy()` was used unsafely to copy a socket path into a fixed-size buffer. The fix replaces the dangerous string copy with `snprintf()`, which provides automatic bounds checking and null-termination. This prevents attackers from exploiting the CLI tool through oversized input arguments.

high

How integer overflow in malloc happens in C libregexp and how to fix it

A high-severity integer overflow vulnerability was discovered in QuickJS's libregexp.c where multiplication to compute allocation size could wrap around, causing a heap overflow. The fix replaces the unsafe `malloc(sizeof(capture[0]) * lre_get_alloc_count(bc))` pattern with `calloc(lre_get_alloc_count(bc), sizeof(capture[0]))`, which safely handles the multiplication internally and prevents exploitation.