Skip to content

scrub() logs a false-positive "unsafe chars" warning for any non-str input (e.g. int chunk IDs) #1015

Description

@deathbywedgie

Summary

tenable.utils.scrub(), updated in #1007 (26.6.1) to fix #1006, logs a spurious warning whenever a non-str value is passed in — even when no characters were actually removed. This fires on every export chunk download, since chunk_id is typed int.

Root cause

def scrub(value: Any) -> str:
    safe_chars = string.ascii_letters + string.digits + '-_%@:'
    scrubbed_value = ''.join([c for c in str(value) if c in safe_chars])
    if value != scrubbed_value:
        logger.warning(
            f"Value '{value}' has unsafe chars, scrubbing to '{scrubbed_value}'"
        )
    return scrubbed_value

scrubbed_value is always a str. When value is not a str (e.g. int, UUID), value != scrubbed_value compares across types, which is unconditionally True in Python regardless of content:

>>> 1 != '1'
True

So the warning fires even though nothing unsafe was stripped.

Where this surfaces in practice

tenable/io/exports/api.py's download_chunk() calls scrub(chunk_id), and chunk_id is declared int | None in tenable/io/exports/iterator.py. Every chunk downloaded during a vulns/assets/compliance export iteration (tio.exports.vulns(), etc.) logs:

[WARNING] tenable.utils: Value '1' has unsafe chars, scrubbing to '1'

...once per chunk, with no actual unsafe content involved.

Reproduction

from tenable.utils import scrub
import logging
logging.basicConfig(level=logging.WARNING)

scrub(1)  # logs: Value '1' has unsafe chars, scrubbing to '1'

Suggested fix

Compare against the stringified original, not the raw value:

scrubbed_value = ''.join([c for c in str(value) if c in safe_chars])
if str(value) != scrubbed_value:
    logger.warning(...)

Note on test coverage

tests/test_utils_scrub.py::test_scrub_int and test_scrub_scan_id_formats both pass non-str/mixed values through scrub() but don't assert on caplog, so this false positive isn't caught by existing tests. Adding a caplog assertion (expect no warning) to those cases would prevent regression.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions