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:
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
Summary
tenable.utils.scrub(), updated in #1007 (26.6.1) to fix #1006, logs a spurious warning whenever a non-strvalue is passed in — even when no characters were actually removed. This fires on every export chunk download, sincechunk_idis typedint.Root cause
scrubbed_valueis always astr. Whenvalueis not astr(e.g.int,UUID),value != scrubbed_valuecompares across types, which is unconditionallyTruein Python regardless of content:So the warning fires even though nothing unsafe was stripped.
Where this surfaces in practice
tenable/io/exports/api.py'sdownload_chunk()callsscrub(chunk_id), andchunk_idis declaredint | Noneintenable/io/exports/iterator.py. Every chunk downloaded during a vulns/assets/compliance export iteration (tio.exports.vulns(), etc.) logs:...once per chunk, with no actual unsafe content involved.
Reproduction
Suggested fix
Compare against the stringified original, not the raw value:
Note on test coverage
tests/test_utils_scrub.py::test_scrub_intandtest_scrub_scan_id_formatsboth pass non-str/mixed values throughscrub()but don't assert oncaplog, so this false positive isn't caught by existing tests. Adding acaplogassertion (expect no warning) to those cases would prevent regression.Environment
main)