T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/ari.py:1474
- Finding
- Arbitrary File Overwrite Through the Export Destination## Vulnerability Details **File Location**: `scripts/ari.py:1474-1475`, with attacker-controlled destination selection at `scripts/ari.py:1582-1597` **Vulnerability Type**: Arbitrary file overwrite and symbolic-link following **Risk Level**: Medium ### Vulnerable Code ```python with open(dest, "wb") as fh: fh.write(body) ``` The destination is derived directly from the command-line `--out` argument: ```python def cmd_export(args): if args.report_id: fmt = args.format or "md" dest = args.out or ("ari_report_%d.%s" % ( args.report_id, "html" if fmt == "html" else "md" )) emit(request_download( "/api/v1/export/reports/%d" % args.report_id, {"format": fmt}, dest ), args.compact) return if not args.asin: emit(error_obj( "ARI_VALIDATION_ERROR", 0, "An ASIN or report ID is required." ), args.compact) return dest = args.out or ("ari_reviews_%s.csv" % args.asin.upper()) emit(request_download( "/api/v1/export/reviews", {"asin": args.asin.upper(), "site": args.site}, dest ), args.compact) ``` ### Technical Analysis The `--out` argument accepts an unrestricted path and passes it to `open(dest, "wb")`. Opening a file in `wb` mode truncates an existing file before writing. The implementation does not: - Restrict output to a dedicated export directory. - Reject absolute paths or parent-directory traversal. - Check whether the destination already exists. - Reject symbolic links. - Use an exclusive or no-follow file creation mode. - Require separate confirmation before replacing an existing file. Export functionality legitimately requires local write access, but unrestricted destructive write access exceeds the minimum filesystem privileges necessary for this task. ### Attack P ...[truncated 1130 chars]
- Remediation
- ## Remediation Suggestions 1. Create a dedicated export directory and resolve every destination relative to it. 2. Reject absolute paths, parent-directory components, and destinations whose resolved path escapes the export directory. 3. Refuse to overwrite existing files by default. 4. Require explicit user confirmation before replacing an existing export. 5. Open new files atomically with exclusive creation, such as `os.open()` with `O_WRONLY | O_CREAT | O_EXCL`. 6. Where supported, add `O_NOFOLLOW` to prevent symbolic-link traversal. 7. Validate both the parent directory and final destination after canonical path resolution. 8. Write to a securely created temporary file in the destination directory and atomically rename it after the download has been fully validated. 9. Apply conservative file permissions, such as `0600`, when exported reports may contain account or review information.
