audit-labs/audit-tools

A collection of scripts, queries, and other goodies you can use in an audit.

clone: git clone https://gitbay.org/audit-labs/audit-tools.git

570c11611346b087353c7cbc0fa294a198d16b37

verified · cmc

author: Christian Cleberg <hello@cleberg.net> · 2026-08-07T02:32:49Z

Harden CLI path handling and sample.html default RNG

SonarCloud security findings:
- load_config / load_json resolve and validate that the input path is a
  regular file before opening (pythonsecurity:S8707)
- sample.html seeds its default draw from crypto.getRandomValues instead of
  Math.random, and writes the seed back so the sample stays reproducible
  (javascript:S2245)
 applications/aws/aws_password_policy/evaluate_policy.py | 5 ++++-
 sampling/sample.html                                    | 9 ++++++++-
 sampling/sampling_tool/cli.py                           | 4 +++-
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/applications/aws/aws_password_policy/evaluate_policy.py b/applications/aws/aws_password_policy/evaluate_policy.py
index 65cd25e..120425b 100755
--- a/applications/aws/aws_password_policy/evaluate_policy.py
+++ b/applications/aws/aws_password_policy/evaluate_policy.py
@@ -109,8 +109,11 @@ def evaluate(expect: Any | None, actual: Any, field_type: str) -> str:
 
 def load_json(path: Path) -> dict[str, Any]:
     """Read the JSON file generated by the Bash script."""
+    resolved = path.resolve()
+    if not resolved.is_file():
+        sys.exit(f"Could not read JSON file {path}: not a regular file")
     try:
-        with path.open("r", encoding="utf-8") as fh:
+        with resolved.open("r", encoding="utf-8") as fh:
             return json.load(fh)
     except Exception as exc:
         sys.exit(f"Could not read JSON file {path}: {exc}")
diff --git a/sampling/sample.html b/sampling/sample.html
index 5a92ab4..950f30b 100644
--- a/sampling/sample.html
+++ b/sampling/sample.html
@@ -77,7 +77,14 @@ function seededRandom(seed) {
 function handleFormSubmit(event) {
     event.preventDefault(); // Prevent the default form submission behavior
     const customSeedInput = document.getElementById('customSeed').value;
-    const seed = customSeedInput ? parseInt(customSeedInput) : Math.floor(Math.random() * 1000000); // Use custom seed if provided
+    // Use the custom seed if provided; otherwise draw a strong random seed and
+    // write it back so the (reproducible) sample can always be tied to a seed.
+    const seed = customSeedInput
+        ? parseInt(customSeedInput)
+        : crypto.getRandomValues(new Uint32Array(1))[0] % 1000000;
+    if (!customSeedInput) {
+        document.getElementById('customSeed').value = seed;
+    }
     generateSamples(seed); // Call the function with the seed
 }
 
diff --git a/sampling/sampling_tool/cli.py b/sampling/sampling_tool/cli.py
index 8ab57ed..ed9a036 100644
--- a/sampling/sampling_tool/cli.py
+++ b/sampling/sampling_tool/cli.py
@@ -54,7 +54,9 @@ def load_config(path: str | None) -> dict[str, object]:
             "YAML config support requires PyYAML. Install requirements.txt."
         ) from exc
 
-    config_path = Path(path)
+    config_path = Path(path).resolve()
+    if not config_path.is_file():
+        raise AuditSamplingError(f"Config file not found: {path}")
     with config_path.open("r", encoding="utf-8") as handle:
         data = yaml.safe_load(handle) or {}
     if not isinstance(data, dict):