Description
TenableOne.inventory.findings.list() sends an empty {} request body to /api/v1/t1/inventory/findings/search when only filters is passed (without query_text and query_mode). The result is the API returns unfiltered findings rather than raising an error or applying the filters.
Root cause
In tenable/tenableone/inventory/findings/api.py, the payload is only constructed when all three of query_text, query_mode, and filters are non-None simultaneously:
payload = {}
# TODO: check what is the actual contract
if query_text is not None and query_mode is not None and filters is not None:
payload = {
"query": {"text": query_text, "mode": query_mode.value},
"filters": [...],
}
Passing only filters falls through to payload = {}.
Steps to reproduce
from tenable.tenableone import TenableOne
from tenable.tenableone.inventory.schema import PropertyFilter, Operator
t1 = TenableOne(access_key="...", secret_key="...")
# Expectation: returns only ACTIVE findings
# Actual: returns all findings (filters silently ignored)
findings = t1.inventory.findings.list(
filters=[
PropertyFilter(property="state", operator=Operator.EQUAL, value=["ACTIVE"]),
]
)
Expected behaviour
Filters should be applied independently of query_text/query_mode. The API accepts a body of {"filters": [...]} without a query key and applies them correctly — the bug is purely in the client-side payload construction.
Verified via direct HTTP call:
[requests.post](http://requests.post/)(
"https://cloud.tenable.com/api/v1/t1/inventory/findings/search?limit=5",
json={"filters": [{"property": "state", "operator": "=", "value": ["ACTIVE"]}]}
)
# Returns filtered results correctly
Suggested fix
Build query and filters keys independently:
payload = {}
if query_text is not None and query_mode is not None:
payload["query"] = {"text": query_text, "mode": query_mode.value}
if filters is not None:
payload["filters"] = [f.model_dump(mode="json") for f in filters]
Environment
- Test date: 2026-08-04
- OS: macOS 26.5.2 (arm64, build 25F84)
- Python: CPython 3.14.5
- pytenable: 26.6.1, installed from PyPI by
uv
- Dependency lock:
uv.lock pins pytenable to 26.6.1
- Project constraint:
pytenable>=26.6,<27
- API base URL:
https://cloud.tenable.com/
- Authentication:
TenableOne(access_key=..., secret_key=...); credentials omitted
The reproduction was checked against the installed pytenable 26.6.1
implementation. The installed distribution does not retain an upstream Git
commit, so latest main (post 2105ee5) is not independently reproducible from
this environment.
Description
TenableOne.inventory.findings.list()sends an empty{}request body to/api/v1/t1/inventory/findings/searchwhen onlyfiltersis passed (withoutquery_textandquery_mode). The result is the API returns unfiltered findings rather than raising an error or applying the filters.Root cause
In
tenable/tenableone/inventory/findings/api.py, the payload is only constructed when all three ofquery_text,query_mode, andfiltersare non-None simultaneously:Passing only
filtersfalls through topayload = {}.Steps to reproduce
Expected behaviour
Filters should be applied independently of
query_text/query_mode. The API accepts a body of{"filters": [...]}without aquerykey and applies them correctly — the bug is purely in the client-side payload construction.Verified via direct HTTP call:
Suggested fix
Build
queryandfilterskeys independently:Environment
uvuv.lockpins pytenable to 26.6.1pytenable>=26.6,<27https://cloud.tenable.com/TenableOne(access_key=..., secret_key=...); credentials omittedThe reproduction was checked against the installed pytenable 26.6.1
implementation. The installed distribution does not retain an upstream Git
commit, so
latest main (post 2105ee5)is not independently reproducible fromthis environment.