Skip to content

Commit

Permalink
Securely extract PyPI .tar.gz archives (#102)
Browse files Browse the repository at this point in the history
* Add Semgrep rule and run custom Semgrep rules in CI for SAST

* Securely extract remote .tar.gz files
  • Loading branch information
christophetd authored Dec 5, 2022
1 parent 8e814de commit 37c7d07
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 5 deletions.
21 changes: 21 additions & 0 deletions .github/semgrep-rules/insecure-unpack-archive.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
rules:
- id: insecure-shutil-unpack-archive-use
message: The Python 'shutil' shutil.extract_archive is vulnerable to
arbitrary file overwrites
languages:
- python
severity: ERROR
metadata:
category: security
technology:
- python
owasp:
- A06:2017 - Security Misconfiguration
- A05:2021 - Security Misconfiguration
cwe:
- "CWE-22: Improper Limitation of a Pathname to a Restricted Directory
('Path Traversal')"
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
pattern-either:
- pattern: |
shutil.unpack_archive(...)
10 changes: 9 additions & 1 deletion .github/workflows/semgrep.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,17 @@ jobs:
- uses: actions/checkout@v3

- run: semgrep --config auto --sarif --output semgrep.sarif ./guarddog
- run: semgrep --config .github/semgrep-rules --sarif --output semgrep-custom.sarif ./guarddog

- name: Upload SARIF file for GitHub Advanced Security Dashboard
uses: github/codeql-action/upload-sarif@v2
with:
category: semgrep-builtin
sarif_file: semgrep.sarif
if: always()

- name: Upload SARIF file for custom Semgrep rules for GitHub Advanced Security Dashboard
uses: github/codeql-action/upload-sarif@v2
with:
category: semgrep-custom
sarif_file: semgrep-custom.sarif

10 changes: 6 additions & 4 deletions guarddog/scanners/package_scanner.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import json
import os
import shutil
import tarsafe # type: ignore
import tarsafe # type:ignore
import tempfile
import requests

Expand Down Expand Up @@ -160,5 +159,8 @@ def download_compressed(self, url, zippath, unzippedpath):
with open(zippath, "wb") as f:
f.write(response.raw.read())

shutil.unpack_archive(zippath, unzippedpath)
os.remove(zippath)
if zippath.endswith('.tar.gz'):
tarsafe.open(zippath).extractall(unzippedpath)
os.remove(zippath)
else:
raise ValueError("unsupported archive extension: " + zippath)

0 comments on commit 37c7d07

Please sign in to comment.