Repository navigation
Description
Bug description
The OpenVAS XML parser creates DefectDojo endpoints.
However, when the XML report contains both an IP address and an optional
hostname/FQDN, only one of these values is retained as the endpoint host.
Observed behavior:
- If
<hostname>contains a value, the DefectDojo endpoint uses the FQDN. - If
<hostname>is empty or absent, the DefectDojo endpoint uses the IP
address from<host>. - When an FQDN is present, the scanner-reported IP address is not retained
in the endpoint.
For the first result, the created DefectDojo endpoint contains only the FQDN:
Host: host01.example.com
Port: 443
Protocol: tcp
The source IP address 192.0.2.10 is not retained.
For the second result, where the FQDN is empty, the endpoint contains the IP:
Host: 192.0.2.11
Port: 443
Protocol: tcp
This means that the endpoint identity changes depending on DNS/hostname
availability in the scan report.
Sanitized OpenVAS XML example
xml
<report>
<results start="1" max="-1">
<result id="00000000-0000-0000-0000-000000000001">
<name>Example Vulnerability</name>
<host>
192.0.2.10
<asset asset_id="00000000-0000-0000-0000-000000000002"/>
<hostname>host01.example.com</hostname>
</host>
<port>443/tcp</port>
<nvt oid="1.3.6.1.4.1.25623.1.0.100000">
<type>nvt</type>
<name>Example NVT</name>
</nvt>
<severity>7.5</severity>
</result>
<result id="00000000-0000-0000-0000-000000000003">
<name>Example Vulnerability</name>
<host>
192.0.2.11
<asset asset_id="00000000-0000-0000-0000-000000000004"/>
<hostname/>
</host>
<port>443/tcp</port>
<nvt oid="1.3.6.1.4.1.25623.1.0.100000">
<type>nvt</type>
<name>Example NVT</name>
</nvt>
<severity>7.5</severity>
</result>
</results>
</report>
Expected behavior
Both values from the scanner report should be preserved:
IP address: 192.0.2.10
Hostname: host01.example.com
Port: 443
Protocol: tcp
Suggested source mapping:
<host>.text -> IP address
<host>/<hostname>.text -> hostname/FQDN, if present
<port> -> endpoint port and protocol
<nvt oid="..."> -> scanner vulnerability identity
The IP address should be the stable technical endpoint identity.
The FQDN should be retained as additional endpoint metadata or as an
endpoint alias.
An FQDN alone is not a stable technical asset identifier:
- DNS resolution can fail temporarily.
- Hostnames can change.
- Multiple hostnames can point to the same IP address.
- A later Greenbone scan may report only the IP address.
The same target can otherwise be represented differently between scans:
Scan 1: host01.example.com
Scan 2: 192.0.2.10
This can negatively affect endpoint correlation, finding deduplication,
and continuous vulnerability management workflows.
The OpenVAS XML source report already provides both values. The IP address
should therefore not be discarded when a hostname is available.
Deployment method
- [ x] Docker Compose
Environment information
- Operating System: Rocky 10
- Podman Compose : 1.6.
- DefectDojo version:
3.2.4 - Deployment:
Podman 5.8.2 - Scan type:
OpenVAS XML
Activity
happymode-25 commentedon Sep 30, 2026
Confirmed, and I think the framing here may be worth adjusting. I dug into the two OpenVAS parsers and the behaviour is real, but the root cause is that v1 and v2 disagree with each other on the same file, and one of them has a dead code path.
The mechanism
<hostname>is nested inside<host>in Greenbone output, never a sibling of it:That matters because the two parsers reach for the host differently:
dojo/tools/openvas/parser_v1/xml_parser.py:27) doesfor field in result:, which only walks direct children of<result>. Itsif field.tag == "hostname"branch at L31 therefore never fires for real GMP output. Only L37-42 (if field.tag == "host") ever setsloc_host, so v1 always uses the IP.dojo/tools/openvas/parser_v2/xml_parser.py:123-132) callsfield.find("hostname"), which does reach into the nested child, and prefers it (L126-129). So v2 always uses the FQDN when one is present.I checked this against the repo's own fixtures rather than reasoning about it:
<result><hostname>direct child<hostname>nested in<host>unittests/scans/openvas/many_vuln.xmlunittests/scans/openvas/report_detail_v2.xmlunittests/scans/openvas/one_vuln.xmlSo the v1
hostnamebranch is unreachable on all 46 results in the fixture set, and the symptom in this report (FQDN wins, IP dropped) is v2 behaviour.The part that worries me more than the report does
Feeding
many_vuln.xmlthrough both parsers, they disagree on 44 of 44 results — zero agreement. And the value v2 prefers looks like this:b6b9f466d63is a 12-character hex string — not a valid IP and not a resolvable name. Greenbone emits container IDs in<hostname>when the scan target is a container, so v2's "prefer the FQDN" rule appears to key those endpoints on an ephemeral container ID, which changes every time the container is recreated.If that's right it's a worse instability than the one reported here — not "sometimes the FQDN, sometimes the IP" but "sometimes the FQDN, sometimes a value that is guaranteed to go stale". I'd treat my read of the Greenbone semantics as an inference from the fixture rather than something I've confirmed against Greenbone's docs, so please correct me if the target really is a normal host.
Why the test suite doesn't catch it
test_openvas_parser_csv_xml_parityonly compares v2-CSV against v2-XML. The v1 test asserts"tcp://192.168.1.1001:512"intest_openvas_xml_many_vuln(the raw<host>text) and the v2 test asserts"server99", a real hostname, but against a different fixture. Both assertions are internally consistent, and nothing compares v1 against v2 on the same input — so the disagreement is invisible.On the "preserve both values" part
I'd push back gently on that half, because I don't think it's a parser fix:
LocationData.url()(dojo/tools/locations.py) accepts exactlyurl, host, port, protocol, path, query, fragment, user_info. There is noipfield, and a code search forLocationData.ip/endpoint.ip/ip=ipacross the tree returns nothing — no parser stores the IP separately today.AbstractLocation.set_identity_hash()(dojo/location/models.py:376-377) isblake2b(str(self)). Location identity is a hash of the rendered location, sohost01.example.com:443and192.0.2.10:443are two different identities. Flipping the parser to prefer the IP wouldn't fix correlation for people who already imported FQDN-based data — it would create a new set of Location rows alongside the old ones on reimport.The correlation problem described here is real, but the fix looks like it belongs in the location model (an
ipattribute, or aliasing), which is a schema and migration decision rather than an OpenVAS bug.What I'd like to do instead
I initially assumed the fix was to make v1 match v2, since
dojo/tools/nmap/parser.py:72-73and77-78usehost=fqdn or ipand v1 is the one deviating. The container-ID observation above makes me think that assumption is wrong: nmap'sfqdncomes from a PTR DNS lookup, so it's a real resolvable name, whereas Greenbone's<hostname>is not reliably a name at all. The nmap convention probably shouldn't be extended to OpenVAS as-is.So I'd rather not guess at the direction. What I can do without prejudging it:
many_vuln.xmlthrough bothOpenVASParserandOpenVASParserV2and assert they agree on host/port/protocol. It fails today on all 44 results, which makes the disagreement explicit and gives you a regression guard whichever way you resolve it. I'm happy to send this as a standalone PR independent of any behaviour change.<host>the way v2 does, or make v2 prefer the<host>text the way v1 does. The v1 L31-36 branch is dead either way and should go.Does the container-ID reading match what you've seen in practice? That's the piece I'd most like confirmed or corrected before I write anything.
One note on the sanitised XML in the report: the parser does
root.find("report"), so the real format nests<report>inside the document element. Worth knowing if anyone reproduces from the snippet as pasted — the host/hostname structure above is accurate though.Whitehorse2 commentedon Oct 4, 2026
@happymode-25 thanks for digging this up and uncovering the underlying parser disagreements and the ephemeral container ID issue.
To add a real-world perspective to this: Having both fields (IP and FQDN) is absolutely critical for anyone operating modern infrastructure with Virtual Hosts, Reverse Proxies (like Nginx/Traefik), or Load Balancers.
Due to SNI (Server Name Indication) routing, it is very common that a single IP address hosts dozens or hundreds of completely distinct web applications, each with its own unique vulnerability profile.
Whichever way the parser is aligned in the short term, in my opinion DefectDojo's location/endpoint model ultimately needs a structural way to store both a stable IP and its associated FQDNs/aliases to handle modern web architectures properly.
Skeletor-Pirate commentedon Nov 8, 2026
Happy to take this on if it's free. I'd follow @happymode-25's breakdown — reconciling the v1/v2 divergence and removing the dead path — plus regression samples for the FQDN+IP cases so the scanner-reported address is retained alongside the hostname, with a test per parser. Could I be assigned? I may take a few days before opening a PR while my other submissions cycle through review.
happymode-25 commentedon Nov 8, 2026
Thanks @Whitehorse2 and @Skeletor-Pirate! Since I already mapped out the root cause and test vectors, I'm working on the parity test and PR now and will submit it shortly.
Skeletor-Pirate commentedon Nov 8, 2026
Saw your update — please go ahead, I'll step aside. Your write-up already did the hard part (v1/v2 divergence, the dead path, and the test vectors), so this is in better hands with it fresh in mind.
happymode-25 commentedon Nov 8, 2026
Thanks @Skeletor-Pirate! I have just opened PR #16734 with the parity fix, removal of the dead path in v1, and tests ensuring scanner-reported IPs and hostnames are retained across both v1 and v2.