Very similar to https://github.com/apache/apr/pull/73

I'm inclined to just close this as "by design". However it seems I'm not
able to close a PR in GitHub, I only have "comment". Is this just me? Maybe
that is because I've changed by GitHub username.

Cheers,
Daniel


Den tis 23 juni 2026 kl 04:10 skrev orbisai0security (via GitHub) <
[email protected]>:

>
> orbisai0security opened a new pull request, #16:
> URL: https://github.com/apache/apr-util/pull/16
>
>    ## Summary
>    Fix critical severity security issue in `buffer/apr_buffer.c`.
>
>    ## Vulnerability
>    | Field | Value |
>    |-------|-------|
>    | **ID** | V-001 |
>    | **Severity** | CRITICAL |
>    | **Scanner** | multi_agent_ai |
>    | **Rule** | `V-001` |
>    | **File** | `buffer/apr_buffer.c:240` |
>    | **Assessment** | Confirmed exploitable |
>
>    **Description**: Multiple memcpy operations in apr_buffer.c copy data
> without validating that the destination buffer has sufficient capacity. The
> code assumes the allocated buffer is large enough but doesn't verify the
> size parameter against destination buffer bounds.
>
>    ## Evidence
>
>    **Exploitation scenario**: An attacker who can control the 'size'
> parameter or the source data passed to apr_buffer_arraydup() or other
> buffer functions can cause buffer overflow.
>
>    **Scanner confirmation**: multi_agent_ai rule `V-001` flagged this
> pattern.
>
>    **Production code**: This file is in the production codebase, not
> test-only code.
>
>    ## Threat Model Context
>
>    This is a local CLI tool - exploitation requires the attacker to
> control command-line arguments or input files.
>
>    ## Changes
>    - Security fix applied
>
>    > **Note**: The following lines in the same file use a similar pattern
> and may also need review: `buffer/apr_buffer.c:255`,
> `buffer/apr_buffer.c:299`, `buffer/apr_buffer.c:385`,
> `buffer/apr_buffer.c:390`, `buffer/apr_buffer.c:395`
>
>    ## Verification
>    - [x] Build passes
>    - [x] Scanner re-scan confirms fix
>    - [x] LLM code review passed
>
>    ## Security Invariant
>    > **Property**: The security boundary is maintained under adversarial
> input
>
>    <details>
>    <summary>Regression test</summary>
>
>    ```c
>    #include <check.h>
>    #include <stdlib.h>
>    #include <string.h>
>    #include "buffer/apr_buffer.h"
>
>    START_TEST(test_apr_buffer_arraydup_bounds_check)
>    {
>        // Invariant: apr_buffer_arraydup must not write beyond allocated
> destination buffer bounds
>        // regardless of input size values
>
>        // Payloads: exploit case (size causing overflow), boundary case
> (zero size), valid input
>        struct {
>            apr_size_t size;
>            int zero_terminated;
>            int nelts;
>            const char *description;
>        } test_cases[] = {
>            {SIZE_MAX, 1, 2, "exploit: size + zero_terminated causes
> overflow"},
>            {0, 0, 1, "boundary: zero size"},
>            {1024, 0, 3, "valid: normal operation"}
>        };
>
>        int num_cases = sizeof(test_cases) / sizeof(test_cases[0]);
>
>        for (int i = 0; i < num_cases; i++) {
>            // Create source buffer array
>            apr_buffer_t *src_array = malloc(test_cases[i].nelts *
> sizeof(apr_buffer_t));
>            ck_assert_ptr_nonnull(src_array);
>
>            // Initialize source buffers with test data
>            for (int j = 0; j < test_cases[i].nelts; j++) {
>                src_array[j].size = test_cases[i].size;
>                src_array[j].zero_terminated =
> test_cases[i].zero_terminated;
>
>                // Allocate source memory if size > 0
>                if (test_cases[i].size > 0) {
>                    src_array[j].d.mem = malloc(test_cases[i].size);
>                    ck_assert_ptr_nonnull(src_array[j].d.mem);
>                    memset(src_array[j].d.mem, 'A', test_cases[i].size);
>                } else {
>                    src_array[j].d.mem = NULL;
>                }
>            }
>
>            // Test the actual function
>            apr_buffer_t *dst_array = NULL;
>            apr_status_t result = apr_buffer_arraydup(&dst_array,
> src_array,
>
>  (apr_buffer_alloc)malloc, NULL,
>                                                      test_cases[i].nelts);
>
>            // Property: Function must either succeed with valid buffers or
> fail gracefully
>            // without writing beyond allocated memory bounds
>            if (result == APR_SUCCESS) {
>                ck_assert_ptr_nonnull(dst_array);
>
>                // Verify each destination buffer was properly allocated
>                for (int j = 0; j < test_cases[i].nelts; j++) {
>                    if (test_cases[i].size + test_cases[i].zero_terminated
> > 0) {
>                        ck_assert_ptr_nonnull(dst_array[j].d.mem);
>                    }
>                    ck_assert_uint_eq(dst_array[j].size,
> test_cases[i].size);
>                    ck_assert_int_eq(dst_array[j].zero_terminated,
> test_cases[i].zero_terminated);
>                }
>
>                // Clean up destination
>                for (int j = 0; j < test_cases[i].nelts; j++) {
>                    if (dst_array[j].d.mem) {
>                        free(dst_array[j].d.mem);
>                    }
>                }
>                free(dst_array);
>            } else {
>                // If function failed, ensure no partial writes corrupted
> memory
>                ck_assert_ptr_null(dst_array);
>            }
>
>            // Clean up source
>            for (int j = 0; j < test_cases[i].nelts; j++) {
>                if (src_array[j].d.mem) {
>                    free(src_array[j].d.mem);
>                }
>            }
>            free(src_array);
>        }
>    }
>    END_TEST
>
>    Suite *security_suite(void)
>    {
>        Suite *s;
>        TCase *tc_core;
>
>        s = suite_create("Security");
>        tc_core = tcase_create("Core");
>
>        tcase_add_test(tc_core, test_apr_buffer_arraydup_bounds_check);
>        suite_add_tcase(s, tc_core);
>
>        return s;
>    }
>
>    int main(void)
>    {
>        int number_failed;
>        Suite *s;
>        SRunner *sr;
>
>        s = security_suite();
>        sr = srunner_create(s);
>
>        srunner_run_all(sr, CK_NORMAL);
>        number_failed = srunner_ntests_failed(sr);
>        srunner_free(sr);
>
>        return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
>    }
>    ```
>
>    </details>
>
>    This test guards against regressions — it's useful independent of the
> code change above.
>
>    ---
>    *Automated security fix by [OrbisAI Security](https://orbisappsec.com)*
>
>
>
> --
> This is an automated message from the Apache Git Service.
> To respond to the message, please log on to GitHub and use the
> URL above to go to the specific comment.
>
> To unsubscribe, e-mail: [email protected]
>
> For queries about this service, please contact Infrastructure at:
> [email protected]
>
>

Reply via email to