You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-commits@axis.apache.org by ro...@apache.org on 2026/01/30 23:21:22 UTC
(axis-axis2-c-core) 07/07: AXIS2C-1708 Modern security hardening: Add OSS-Fuzz integration for continuous security testing
This is an automated email from the ASF dual-hosted git repository.
robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git
commit 4202b807b56b4a538a102993fe0f9c570074ccd9
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Fri Jan 30 13:00:19 2026 -1000
AXIS2C-1708 Modern security hardening: Add OSS-Fuzz integration for continuous security testing
Fuzz targets:
- fuzz_xml_parser.c: AXIOM XML/SOAP parsing (XXE, XML bombs)
- fuzz_json_parser.c: JSON parsing for HTTP/2 mode (CVE-2020-12762)
- fuzz_http_header.c: HTTP header/request/status parsing
- fuzz_url_parser.c: URL parsing (SSRF, malformed URLs)
Includes:
- Seed corpus files for each parser type
- OSS-Fuzz project files (Dockerfile, build.sh, project.yaml)
- Documentation in docs/OSS-Fuzz.md
Co-Authored-By: Claude Opus 4.5 <no...@anthropic.com>
---
docs/OSS-Fuzz.md | 110 +++++++++++++++++++++++++++
docs/SECURITY.md | 54 +++++++++++++
fuzz/corpus/http/content_type_header.txt | 1 +
fuzz/corpus/http/get_request.txt | 1 +
fuzz/corpus/http/post_request.txt | 1 +
fuzz/corpus/http/status_200.txt | 1 +
fuzz/corpus/json/deep_nesting.json | 1 +
fuzz/corpus/json/valid_array.json | 1 +
fuzz/corpus/json/valid_object.json | 1 +
fuzz/corpus/url/http_url.txt | 1 +
fuzz/corpus/url/https_url.txt | 1 +
fuzz/corpus/xml/namespaces.xml | 4 +
fuzz/corpus/xml/simple_element.xml | 2 +
fuzz/corpus/xml/soap_envelope.xml | 6 ++
fuzz/fuzz_http_header.c | 118 +++++++++++++++++++++++++++++
fuzz/fuzz_json_parser.c | 102 +++++++++++++++++++++++++
fuzz/fuzz_url_parser.c | 96 ++++++++++++++++++++++++
fuzz/fuzz_xml_parser.c | 125 +++++++++++++++++++++++++++++++
fuzz/oss-fuzz/Dockerfile | 32 ++++++++
fuzz/oss-fuzz/build.sh | 60 +++++++++++++++
fuzz/oss-fuzz/project.yaml | 27 +++++++
21 files changed, 745 insertions(+)
diff --git a/docs/OSS-Fuzz.md b/docs/OSS-Fuzz.md
new file mode 100644
index 000000000..812e55ac6
--- /dev/null
+++ b/docs/OSS-Fuzz.md
@@ -0,0 +1,110 @@
+# OSS-Fuzz Integration for Apache Axis2/C
+
+## What is Fuzz Testing?
+
+Fuzz testing (fuzzing) automatically generates random, malformed, or unexpected inputs to find bugs that manual testing misses. It's especially effective at discovering:
+
+- Buffer overflows and memory corruption
+- Crashes from malformed input
+- Integer overflows
+- Denial of service vulnerabilities
+
+## What is OSS-Fuzz?
+
+[OSS-Fuzz](https://github.com/google/oss-fuzz) is Google's free continuous fuzzing service for open source projects. Once integrated, it runs 24/7 on Google's infrastructure, automatically:
+
+- Testing your code with millions of inputs daily
+- Reporting crashes and vulnerabilities privately
+- Tracking bug fixes and regressions
+
+## Eligibility
+
+Apache Axis2/C qualifies for OSS-Fuzz because it:
+
+1. **Is widely used** - Deployed in enterprise SOAP/web services
+2. **Processes untrusted input** - Parses XML, JSON, HTTP from network
+3. **Is open source** - Apache License 2.0
+4. **Has an active community** - Apache Software Foundation project
+
+Other Apache projects using OSS-Fuzz include Apache httpd (which Axis2/C uses as a dependency), Apache Commons, and Apache Tomcat.
+
+## Fuzz Targets
+
+The `fuzz/` directory contains these targets:
+
+| Target | Tests | Security Focus |
+|--------|-------|----------------|
+| `fuzz_xml_parser.c` | AXIOM XML/SOAP parsing | XXE, XML bombs, buffer overflows |
+| `fuzz_json_parser.c` | JSON parsing (HTTP/2 mode) | DoS, integer overflows (CVE-2020-12762) |
+| `fuzz_http_header.c` | HTTP header/request/status parsing | Header injection, buffer overflows |
+| `fuzz_url_parser.c` | URL parsing | SSRF, malformed URLs |
+
+## Local Testing
+
+### Prerequisites
+
+```bash
+# Install clang with fuzzer support
+sudo apt-get install clang llvm
+
+# Build Axis2/C with AddressSanitizer
+export CC=clang
+export CFLAGS="-fsanitize=address,fuzzer-no-link -g"
+./configure --prefix=/usr/local
+make
+```
+
+### Run a Fuzz Target Locally
+
+```bash
+# Compile fuzz target
+clang -fsanitize=address,fuzzer \
+ -I/usr/local/include/axis2-2.0.0 \
+ -I/usr/local/include/axis2-2.0.0/platforms \
+ fuzz/fuzz_http_header.c \
+ -L/usr/local/lib -laxis2_http_sender -laxutil \
+ -o fuzz_http_header
+
+# Run with seed corpus
+./fuzz_http_header fuzz/corpus/http/
+
+# Run for 60 seconds
+./fuzz_http_header -max_total_time=60 fuzz/corpus/http/
+```
+
+## OSS-Fuzz Project Setup
+
+To submit Axis2/C to OSS-Fuzz, create a PR to [google/oss-fuzz](https://github.com/google/oss-fuzz) with:
+
+```
+projects/axis2c/
+├── Dockerfile # Build environment
+├── build.sh # Compilation script
+├── project.yaml # Project metadata
+```
+
+See `fuzz/oss-fuzz/` for ready-to-use templates.
+
+## Seed Corpus
+
+The `fuzz/corpus/` directory contains seed inputs that help the fuzzer explore code paths faster:
+
+- `corpus/xml/` - SOAP envelopes, XML with namespaces
+- `corpus/json/` - Valid JSON objects, arrays, nested structures
+- `corpus/http/` - HTTP request lines, headers, status lines
+- `corpus/url/` - HTTP/HTTPS URLs with various components
+
+## Handling Bug Reports
+
+When OSS-Fuzz finds a bug:
+
+1. You receive a private email with crash details
+2. Fix the bug within 90 days (before public disclosure)
+3. OSS-Fuzz automatically verifies the fix
+4. After 30 days of being fixed, the bug report becomes public
+
+## Resources
+
+- [OSS-Fuzz Documentation](https://google.github.io/oss-fuzz/)
+- [libFuzzer Tutorial](https://llvm.org/docs/LibFuzzer.html)
+- [Fuzzing Best Practices](https://google.github.io/oss-fuzz/getting-started/new-project-guide/)
diff --git a/docs/SECURITY.md b/docs/SECURITY.md
index e5dca2345..a8ae11e1c 100644
--- a/docs/SECURITY.md
+++ b/docs/SECURITY.md
@@ -835,3 +835,57 @@ Security hardening commits are reviewed using Google Gemini AI for:
2. Strong cipher suites configured (AEAD with forward secrecy)
3. JSON payload size limits enforced in HTTP/2 streaming mode
4. Improved error messages include source context for debugging
+
+## OSS-Fuzz Integration
+
+Apache Axis2/C includes fuzz testing infrastructure for integration with
+[OSS-Fuzz](https://github.com/google/oss-fuzz), Google's continuous fuzzing
+service for open source projects.
+
+### Fuzz Targets
+
+The `fuzz/` directory contains libFuzzer-compatible targets:
+
+| Target | Component Tested | Security Focus |
+|--------|------------------|----------------|
+| `fuzz_xml_parser.c` | AXIOM XML/SOAP parsing | XXE, XML bombs, buffer overflows |
+| `fuzz_json_parser.c` | JSON parsing (HTTP/2 mode) | DoS (CVE-2020-12762), integer overflows |
+| `fuzz_http_header.c` | HTTP header/request/status parsing | Header injection, buffer overflows |
+| `fuzz_url_parser.c` | URL parsing | SSRF, malformed URL handling |
+
+### Running Fuzz Tests Locally
+
+```bash
+# Build with fuzzing instrumentation
+export CC=clang
+export CFLAGS="-fsanitize=address,fuzzer-no-link -g"
+./configure --prefix=/usr/local
+make && make install
+
+# Compile and run a fuzz target
+clang -fsanitize=address,fuzzer \
+ -I/usr/local/include/axis2-2.0.0 \
+ -I/usr/local/include/axis2-2.0.0/platforms \
+ fuzz/fuzz_http_header.c \
+ -L/usr/local/lib -laxis2_http_sender -laxutil \
+ -o fuzz_http_header
+
+./fuzz_http_header fuzz/corpus/http/ -max_total_time=300
+```
+
+### OSS-Fuzz Project Files
+
+Ready-to-submit project files are in `fuzz/oss-fuzz/`:
+- `Dockerfile` - Build environment with dependencies
+- `build.sh` - Compilation script for all fuzz targets
+- `project.yaml` - Project metadata for Google
+
+### Seed Corpus
+
+Initial test cases in `fuzz/corpus/` help the fuzzer explore code paths:
+- `corpus/xml/` - SOAP envelopes, elements with namespaces
+- `corpus/json/` - Valid JSON objects, arrays, nested structures
+- `corpus/http/` - HTTP request lines, headers, status lines
+- `corpus/url/` - HTTP/HTTPS URLs with various components
+
+For complete setup instructions, see [docs/OSS-Fuzz.md](OSS-Fuzz.md).
diff --git a/fuzz/corpus/http/content_type_header.txt b/fuzz/corpus/http/content_type_header.txt
new file mode 100644
index 000000000..3a3fdc3c2
--- /dev/null
+++ b/fuzz/corpus/http/content_type_header.txt
@@ -0,0 +1 @@
+Content-Type: application/soap+xml; charset=utf-8
\ No newline at end of file
diff --git a/fuzz/corpus/http/get_request.txt b/fuzz/corpus/http/get_request.txt
new file mode 100644
index 000000000..138ba6509
--- /dev/null
+++ b/fuzz/corpus/http/get_request.txt
@@ -0,0 +1 @@
+GET /services/echo HTTP/1.1
\ No newline at end of file
diff --git a/fuzz/corpus/http/post_request.txt b/fuzz/corpus/http/post_request.txt
new file mode 100644
index 000000000..45fa8ce1f
--- /dev/null
+++ b/fuzz/corpus/http/post_request.txt
@@ -0,0 +1 @@
+POST /axis2/services/Version HTTP/1.1
\ No newline at end of file
diff --git a/fuzz/corpus/http/status_200.txt b/fuzz/corpus/http/status_200.txt
new file mode 100644
index 000000000..9cc3d47d0
--- /dev/null
+++ b/fuzz/corpus/http/status_200.txt
@@ -0,0 +1 @@
+HTTP/1.1 200 OK
\ No newline at end of file
diff --git a/fuzz/corpus/json/deep_nesting.json b/fuzz/corpus/json/deep_nesting.json
new file mode 100644
index 000000000..a57b3575f
--- /dev/null
+++ b/fuzz/corpus/json/deep_nesting.json
@@ -0,0 +1 @@
+{"a":{"b":{"c":{"d":{"e":{"f":"deep"}}}}}}
\ No newline at end of file
diff --git a/fuzz/corpus/json/valid_array.json b/fuzz/corpus/json/valid_array.json
new file mode 100644
index 000000000..0e6907543
--- /dev/null
+++ b/fuzz/corpus/json/valid_array.json
@@ -0,0 +1 @@
+[1,2,3,"string",null,true,false,{"nested":"object"}]
\ No newline at end of file
diff --git a/fuzz/corpus/json/valid_object.json b/fuzz/corpus/json/valid_object.json
new file mode 100644
index 000000000..a0220e649
--- /dev/null
+++ b/fuzz/corpus/json/valid_object.json
@@ -0,0 +1 @@
+{"name":"test","value":123,"nested":{"key":"value"}}
\ No newline at end of file
diff --git a/fuzz/corpus/url/http_url.txt b/fuzz/corpus/url/http_url.txt
new file mode 100644
index 000000000..ce8ed5d22
--- /dev/null
+++ b/fuzz/corpus/url/http_url.txt
@@ -0,0 +1 @@
+http://localhost:8080/axis2/services/Echo
\ No newline at end of file
diff --git a/fuzz/corpus/url/https_url.txt b/fuzz/corpus/url/https_url.txt
new file mode 100644
index 000000000..c7222444f
--- /dev/null
+++ b/fuzz/corpus/url/https_url.txt
@@ -0,0 +1 @@
+https://example.com:443/path/to/service?param=value
\ No newline at end of file
diff --git a/fuzz/corpus/xml/namespaces.xml b/fuzz/corpus/xml/namespaces.xml
new file mode 100644
index 000000000..d67ea4432
--- /dev/null
+++ b/fuzz/corpus/xml/namespaces.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<ns1:root xmlns:ns1="http://example.org/ns1" xmlns:ns2="http://example.org/ns2">
+ <ns2:child ns1:attr="value">content</ns2:child>
+</ns1:root>
\ No newline at end of file
diff --git a/fuzz/corpus/xml/simple_element.xml b/fuzz/corpus/xml/simple_element.xml
new file mode 100644
index 000000000..7b0a2be31
--- /dev/null
+++ b/fuzz/corpus/xml/simple_element.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<root attr="value"><child>text</child></root>
\ No newline at end of file
diff --git a/fuzz/corpus/xml/soap_envelope.xml b/fuzz/corpus/xml/soap_envelope.xml
new file mode 100644
index 000000000..e1bcee9c7
--- /dev/null
+++ b/fuzz/corpus/xml/soap_envelope.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
+ <soapenv:Body>
+ <echo>test</echo>
+ </soapenv:Body>
+</soapenv:Envelope>
\ No newline at end of file
diff --git a/fuzz/fuzz_http_header.c b/fuzz/fuzz_http_header.c
new file mode 100644
index 000000000..0ce2260a4
--- /dev/null
+++ b/fuzz/fuzz_http_header.c
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file fuzz_http_header.c
+ * @brief OSS-Fuzz target for Axis2/C HTTP header parser
+ *
+ * Tests HTTP/1.1 header parsing for buffer overflows, header injection,
+ * and malformed input handling.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <axutil_env.h>
+#include <axutil_allocator.h>
+#include <axutil_error_default.h>
+#include <axutil_log_default.h>
+#include <axis2_http_header.h>
+#include <axis2_http_request_line.h>
+#include <axis2_http_status_line.h>
+
+static axutil_env_t *g_env = NULL;
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ axutil_allocator_t *allocator = axutil_allocator_init(NULL);
+ if (!allocator) return -1;
+
+ axutil_error_t *error = axutil_error_create(allocator);
+ axutil_log_t *log = axutil_log_create(allocator, NULL, NULL);
+
+ g_env = axutil_env_create_with_error_log(allocator, error, log);
+ if (!g_env) return -1;
+
+ axutil_log_set_level(g_env, AXIS2_LOG_LEVEL_CRITICAL);
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (!g_env || size == 0 || size > 64 * 1024) {
+ return 0; /* Skip empty or oversized inputs */
+ }
+
+ /* Null-terminate the input for string functions */
+ char *input = (char *)malloc(size + 1);
+ if (!input) return 0;
+ memcpy(input, data, size);
+ input[size] = '\0';
+
+ /* Test HTTP header parsing */
+ axis2_http_header_t *header = axis2_http_header_create_by_str(g_env, input);
+ if (header) {
+ /* Exercise header accessors */
+ const axis2_char_t *name = axis2_http_header_get_name(header, g_env);
+ const axis2_char_t *value = axis2_http_header_get_value(header, g_env);
+ (void)name;
+ (void)value;
+
+ /* Test serialization */
+ axis2_char_t *str = axis2_http_header_to_external_form(header, g_env);
+ if (str) {
+ AXIS2_FREE(g_env->allocator, str);
+ }
+
+ axis2_http_header_free(header, g_env);
+ }
+
+ /* Test HTTP request line parsing */
+ axis2_http_request_line_t *req_line = axis2_http_request_line_parse_line(
+ g_env, input);
+ if (req_line) {
+ const axis2_char_t *method = axis2_http_request_line_get_method(
+ req_line, g_env);
+ const axis2_char_t *uri = axis2_http_request_line_get_uri(
+ req_line, g_env);
+ const axis2_char_t *version = axis2_http_request_line_get_http_version(
+ req_line, g_env);
+ (void)method;
+ (void)uri;
+ (void)version;
+
+ axis2_http_request_line_free(req_line, g_env);
+ }
+
+ /* Test HTTP status line parsing */
+ axis2_http_status_line_t *status_line = axis2_http_status_line_create(
+ g_env, input);
+ if (status_line) {
+ int code = axis2_http_status_line_get_status_code(status_line, g_env);
+ const axis2_char_t *reason = axis2_http_status_line_get_reason_phrase(
+ status_line, g_env);
+ (void)code;
+ (void)reason;
+
+ axis2_http_status_line_free(status_line, g_env);
+ }
+
+ free(input);
+ return 0;
+}
diff --git a/fuzz/fuzz_json_parser.c b/fuzz/fuzz_json_parser.c
new file mode 100644
index 000000000..3a5cb99f6
--- /dev/null
+++ b/fuzz/fuzz_json_parser.c
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file fuzz_json_parser.c
+ * @brief OSS-Fuzz target for Axis2/C JSON parser
+ *
+ * Tests the json-c integration in Axis2/C HTTP/2 JSON mode.
+ * Targets: CVE-2020-12762 (integer overflow), stack exhaustion,
+ * malformed JSON handling.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <axutil_env.h>
+#include <axutil_allocator.h>
+#include <axutil_error_default.h>
+#include <axutil_log_default.h>
+#include <axis2_json_reader.h>
+
+/* Persistent environment for efficiency (reused across fuzzer iterations) */
+static axutil_env_t *g_env = NULL;
+
+/**
+ * One-time initialization (called by libFuzzer)
+ */
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ axutil_allocator_t *allocator = axutil_allocator_init(NULL);
+ if (!allocator) return -1;
+
+ axutil_error_t *error = axutil_error_create(allocator);
+ axutil_log_t *log = axutil_log_create(allocator, NULL, NULL);
+
+ g_env = axutil_env_create_with_error_log(allocator, error, log);
+ if (!g_env) return -1;
+
+ /* Suppress log output during fuzzing */
+ axutil_log_set_level(g_env, AXIS2_LOG_LEVEL_CRITICAL);
+
+ return 0;
+}
+
+/**
+ * Main fuzzer entry point - called millions of times with random data
+ */
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (!g_env || size == 0 || size > 10 * 1024 * 1024) {
+ return 0; /* Skip empty or oversized inputs */
+ }
+
+ /* Create JSON reader from arbitrary input bytes */
+ axis2_json_reader_t *reader = axis2_json_reader_create_for_memory(
+ g_env, (void *)data, (int)size);
+
+ if (reader) {
+ /* Attempt to parse - should handle any input without crashing */
+ json_object *root = axis2_json_reader_get_root(reader, g_env);
+
+ /* If parsing succeeded, try to access the structure */
+ if (root) {
+ /* Exercise various json-c operations */
+ json_type type = json_object_get_type(root);
+ (void)type; /* Prevent unused warning */
+
+ if (json_object_is_type(root, json_type_object)) {
+ json_object_object_foreach(root, key, val) {
+ (void)key;
+ (void)val;
+ }
+ } else if (json_object_is_type(root, json_type_array)) {
+ size_t len = json_object_array_length(root);
+ for (size_t i = 0; i < len && i < 100; i++) {
+ json_object *item = json_object_array_get_idx(root, i);
+ (void)item;
+ }
+ }
+ }
+
+ axis2_json_reader_free(reader, g_env);
+ }
+
+ return 0;
+}
diff --git a/fuzz/fuzz_url_parser.c b/fuzz/fuzz_url_parser.c
new file mode 100644
index 000000000..474524da0
--- /dev/null
+++ b/fuzz/fuzz_url_parser.c
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file fuzz_url_parser.c
+ * @brief OSS-Fuzz target for Axis2/C URL parsing
+ *
+ * Tests URL parsing for:
+ * - Buffer overflows in URL component extraction
+ * - SSRF-style URL manipulation
+ * - Malformed URL handling
+ * - URL encoding/decoding edge cases
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <axutil_env.h>
+#include <axutil_allocator.h>
+#include <axutil_error_default.h>
+#include <axutil_log_default.h>
+#include <axutil_url.h>
+
+static axutil_env_t *g_env = NULL;
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ axutil_allocator_t *allocator = axutil_allocator_init(NULL);
+ if (!allocator) return -1;
+
+ axutil_error_t *error = axutil_error_create(allocator);
+ axutil_log_t *log = axutil_log_create(allocator, NULL, NULL);
+
+ g_env = axutil_env_create_with_error_log(allocator, error, log);
+ if (!g_env) return -1;
+
+ axutil_log_set_level(g_env, AXIS2_LOG_LEVEL_CRITICAL);
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ axutil_url_t *url = NULL;
+
+ if (!g_env || size == 0 || size > 8192) {
+ return 0; /* Skip empty or oversized inputs */
+ }
+
+ /* Null-terminate for string functions */
+ char *input = (char *)malloc(size + 1);
+ if (!input) return 0;
+ memcpy(input, data, size);
+ input[size] = '\0';
+
+ /* Test URL parsing */
+ url = axutil_url_parse_string(g_env, input);
+ if (url) {
+ /* Exercise URL accessors */
+ axis2_char_t *protocol = axutil_url_get_protocol(url, g_env);
+ axis2_char_t *host = axutil_url_get_host(url, g_env);
+ int port = axutil_url_get_port(url, g_env);
+ axis2_char_t *path = axutil_url_get_path(url, g_env);
+
+ (void)protocol;
+ (void)host;
+ (void)port;
+ (void)path;
+
+ /* Test URL serialization */
+ axis2_char_t *url_str = axutil_url_to_external_form(url, g_env);
+ if (url_str) {
+ AXIS2_FREE(g_env->allocator, url_str);
+ }
+
+ axutil_url_free(url, g_env);
+ }
+
+ free(input);
+ return 0;
+}
diff --git a/fuzz/fuzz_xml_parser.c b/fuzz/fuzz_xml_parser.c
new file mode 100644
index 000000000..f1d00b1fa
--- /dev/null
+++ b/fuzz/fuzz_xml_parser.c
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file fuzz_xml_parser.c
+ * @brief OSS-Fuzz target for Axis2/C XML/SOAP parsing via AXIOM
+ *
+ * Tests AXIOM XML parsing for memory safety issues including:
+ * - Buffer overflows in XML element/attribute handling
+ * - XXE (XML External Entity) injection attempts
+ * - Billion laughs / XML bomb attacks
+ * - Malformed XML handling
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <axutil_env.h>
+#include <axutil_allocator.h>
+#include <axutil_error_default.h>
+#include <axutil_log_default.h>
+#include <axiom.h>
+#include <axiom_xml_reader.h>
+#include <axiom_stax_builder.h>
+
+static axutil_env_t *g_env = NULL;
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ axutil_allocator_t *allocator = axutil_allocator_init(NULL);
+ if (!allocator) return -1;
+
+ axutil_error_t *error = axutil_error_create(allocator);
+ axutil_log_t *log = axutil_log_create(allocator, NULL, NULL);
+
+ g_env = axutil_env_create_with_error_log(allocator, error, log);
+ if (!g_env) return -1;
+
+ axutil_log_set_level(g_env, AXIS2_LOG_LEVEL_CRITICAL);
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ axiom_xml_reader_t *xml_reader = NULL;
+ axiom_stax_builder_t *builder = NULL;
+ axiom_document_t *document = NULL;
+ axiom_node_t *root_node = NULL;
+
+ if (!g_env || size == 0 || size > 1024 * 1024) {
+ return 0; /* Skip empty or oversized inputs */
+ }
+
+ /* Create XML reader from memory buffer */
+ xml_reader = axiom_xml_reader_create_for_memory(
+ g_env, (void *)data, (int)size, NULL, AXIS2_XML_PARSER_TYPE_BUFFER);
+
+ if (!xml_reader) {
+ return 0;
+ }
+
+ /* Create StAX builder */
+ builder = axiom_stax_builder_create(g_env, xml_reader);
+ if (!builder) {
+ axiom_xml_reader_free(xml_reader, g_env);
+ return 0;
+ }
+
+ /* Get document and try to parse */
+ document = axiom_stax_builder_get_document(builder, g_env);
+ if (document) {
+ /* Try to get root element - this triggers full parsing */
+ root_node = axiom_document_get_root_element(document, g_env);
+
+ if (root_node) {
+ /* Exercise the parsed tree */
+ axiom_element_t *root_elem = NULL;
+ root_elem = axiom_node_get_data_element(root_node, g_env);
+
+ if (root_elem) {
+ /* Get element name and namespace */
+ axis2_char_t *name = axiom_element_get_localname(root_elem, g_env);
+ axiom_namespace_t *ns = axiom_element_get_namespace(
+ root_elem, g_env, root_node);
+ (void)name;
+ (void)ns;
+
+ /* Iterate children */
+ axiom_node_t *child = axiom_node_get_first_child(root_node, g_env);
+ int child_count = 0;
+ while (child && child_count < 100) {
+ child = axiom_node_get_next_sibling(child, g_env);
+ child_count++;
+ }
+
+ /* Try serialization */
+ axis2_char_t *xml_str = axiom_node_to_string(root_node, g_env);
+ if (xml_str) {
+ AXIS2_FREE(g_env->allocator, xml_str);
+ }
+ }
+ }
+ }
+
+ /* Cleanup - builder frees the reader */
+ axiom_stax_builder_free(builder, g_env);
+
+ return 0;
+}
diff --git a/fuzz/oss-fuzz/Dockerfile b/fuzz/oss-fuzz/Dockerfile
new file mode 100644
index 000000000..6298fc4b3
--- /dev/null
+++ b/fuzz/oss-fuzz/Dockerfile
@@ -0,0 +1,32 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FROM gcr.io/oss-fuzz-base/base-builder
+
+# Install dependencies
+RUN apt-get update && apt-get install -y \
+ autoconf \
+ automake \
+ libtool \
+ pkg-config \
+ libxml2-dev \
+ libssl-dev \
+ libjson-c-dev \
+ zlib1g-dev
+
+# Clone Axis2/C source
+RUN git clone --depth 1 https://github.com/apache/axis-axis2-c-core.git axis2c
+
+WORKDIR axis2c
+COPY build.sh $SRC/
diff --git a/fuzz/oss-fuzz/build.sh b/fuzz/oss-fuzz/build.sh
new file mode 100755
index 000000000..6dad45073
--- /dev/null
+++ b/fuzz/oss-fuzz/build.sh
@@ -0,0 +1,60 @@
+#!/bin/bash -eu
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Build Axis2/C with fuzzing instrumentation
+cd $SRC/axis2c
+
+# Configure with fuzzing flags
+./configure \
+ --prefix=$WORK/install \
+ --enable-static \
+ --disable-shared \
+ CFLAGS="$CFLAGS" \
+ LDFLAGS="$LDFLAGS"
+
+make -j$(nproc)
+make install
+
+# Build fuzz targets
+AXIS2_INCLUDES="-I$WORK/install/include/axis2-2.0.0 -I$WORK/install/include/axis2-2.0.0/platforms"
+AXIS2_LIBS="$WORK/install/lib/libaxis2_axiom.a \
+ $WORK/install/lib/libaxis2_parser.a \
+ $WORK/install/lib/libaxutil.a \
+ $WORK/install/lib/libaxis2_http_sender.a \
+ $WORK/install/lib/libaxis2_http_receiver.a \
+ $WORK/install/lib/libaxis2_http_common.a \
+ $WORK/install/lib/libaxis2_engine.a"
+SYS_LIBS="-lxml2 -lssl -lcrypto -ljson-c -lz -lpthread"
+
+# Compile each fuzz target
+for target in fuzz_xml_parser fuzz_json_parser fuzz_http_header fuzz_url_parser; do
+ $CC $CFLAGS $AXIS2_INCLUDES \
+ fuzz/${target}.c \
+ -o $OUT/${target} \
+ $LIB_FUZZING_ENGINE \
+ $AXIS2_LIBS $SYS_LIBS $LDFLAGS
+done
+
+# Copy seed corpora
+for corpus_dir in xml json http url; do
+ if [ -d "fuzz/corpus/${corpus_dir}" ]; then
+ zip -j $OUT/fuzz_${corpus_dir}_parser_seed_corpus.zip fuzz/corpus/${corpus_dir}/* 2>/dev/null || true
+ fi
+done
+
+# HTTP corpus goes to http_header target
+if [ -f "$OUT/fuzz_http_parser_seed_corpus.zip" ]; then
+ mv $OUT/fuzz_http_parser_seed_corpus.zip $OUT/fuzz_http_header_seed_corpus.zip
+fi
diff --git a/fuzz/oss-fuzz/project.yaml b/fuzz/oss-fuzz/project.yaml
new file mode 100644
index 000000000..28d38d6fa
--- /dev/null
+++ b/fuzz/oss-fuzz/project.yaml
@@ -0,0 +1,27 @@
+# Project metadata for OSS-Fuzz
+# See: https://google.github.io/oss-fuzz/getting-started/new-project-guide/
+
+homepage: "https://axis.apache.org/axis2/c/core/"
+language: c
+primary_contact: "dev@axis.apache.org"
+auto_ccs:
+ - "security@apache.org"
+
+# Supported fuzzing engines
+fuzzing_engines:
+ - libfuzzer
+ - afl
+ - honggfuzz
+
+# Supported sanitizers
+sanitizers:
+ - address
+ - undefined
+ - memory
+
+# Main repository
+main_repo: "https://github.com/apache/axis-axis2-c-core.git"
+
+# Vendor - Apache Software Foundation
+vendor_ccs:
+ - "security@apache.org"