Skip to content

Commit 7c88141

Browse files
author
James Campbell
committed
Fix security vulnerabilities: update dependencies and remove hardcoded secrets
- Update filelock 3.20.0 -> 3.20.2 (GHSA-w853-jp5j-5j7f) - Update fonttools 4.60.1 -> 4.61.1 (GHSA-768j-98cg-p3fv) - Update scapy 2.6.1 -> 2.7.0 (GHSA-cq46-m9x9-j8w2) - Update urllib3 2.5.0 -> 2.6.2 (GHSA-2xpw-w6gg-jr37, GHSA-gm62-xv2j-4w53) - Remove hardcoded API keys from instagram_geo-example.py - Remove hardcoded database password from hug-postgresql-example.py - Fix SQL injection vulnerability with parameterized queries - Add secret scanning workflow - Add configs.py.example template - Add Dependabot configuration
1 parent 9d902b1 commit 7c88141

File tree

9 files changed

+221
-57
lines changed

9 files changed

+221
-57
lines changed

.github/dependabot.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
open-pull-requests-limit: 10
8+
ignore:
9+
# pip 25.2 vulnerability - NOT AFFECTED (Python 3.12+ implements PEP 706)
10+
- dependency-name: "pip"
11+
versions: ["25.2"]
12+
# scrapy already at latest version, old vulnerability from 2017
13+
- dependency-name: "scrapy"
14+
versions: ["2.13.3"]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Secret Scanning
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
schedule:
9+
- cron: '0 0 * * 0' # Weekly scan
10+
11+
jobs:
12+
secret-scanning:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0 # Full history for better detection
18+
19+
- name: Run Gitleaks
20+
uses: gitleaks/gitleaks-action@v2
21+
env:
22+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23+
24+
- name: Check for hardcoded secrets
25+
run: |
26+
echo "Checking for common secret patterns..."
27+
# Check for hardcoded API keys, passwords, tokens
28+
if grep -rE "(api[_-]?key|apikey|secret|password|token|auth|credential|private[_-]?key)\s*=\s*['\"][^'\"]{10,}" --include="*.py" python-examples/ | grep -v "configs.py" | grep -v "from configs import" | grep -v "os.getenv" | grep -v "input(" | grep -v "#.*example" | grep -v "yoursecretkey" | grep -v "your.*token"; then
29+
echo "::error::Found potential hardcoded secrets in code!"
30+
exit 1
31+
fi
32+
echo "No hardcoded secrets found"

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,29 @@ uv run isort .
5757
- **assets/**: Sample data files for examples
5858
- **tests/**: Test files
5959
- **.github/workflows/**: GitHub Actions for CI/CD
60+
- **configs.py.example**: Template for API keys and credentials (copy to `configs.py`)
61+
62+
## 🔐 Security & Configuration
63+
64+
### Setting Up API Keys
65+
66+
Many examples require API keys or credentials. To use them:
67+
68+
1. Copy the example config file:
69+
```bash
70+
cp configs.py.example configs.py
71+
```
72+
73+
2. Edit `configs.py` and add your actual API keys (this file is gitignored)
74+
75+
3. Alternatively, use environment variables:
76+
```bash
77+
export FOURSQUARE_CLIENT_ID="your_key"
78+
export FOURSQUARE_CLIENT_SECRET="your_secret"
79+
export DB_PASSWORD="your_password"
80+
```
81+
82+
**⚠️ Never commit `configs.py` to version control!** It's already in `.gitignore`.
6083

6184
## 🤖 LLM & AI Examples
6285

configs.py.example

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
Example configuration file for python-examples.
3+
4+
Copy this file to configs.py and fill in your actual API keys and credentials.
5+
NEVER commit configs.py to version control - it's already in .gitignore
6+
"""
7+
8+
# Foursquare API (for instagram_geo-example.py)
9+
foursquare_client_id = "your_foursquare_client_id_here"
10+
foursquare_client_secret = "your_foursquare_client_secret_here"
11+
12+
# Quandl API (for quandl-example.py)
13+
myqkey = "your_quandl_api_key_here"
14+
15+
# Pinboard API (for pinboard-example.py)
16+
# Get your token at https://pinboard.in/settings/password
17+
pinapi = "your_username:your_api_token"
18+
19+
# Shodan API (for shodan-example.py)
20+
globalshodankey = "your_shodan_api_key_here"
21+
22+
# Zillow API (for pyzillow-example.py)
23+
zillowapi = "your_zillow_api_key_here"
24+
25+
# PostgreSQL Database (for hug-postgresql-example.py)
26+
db_name = "your_database_name"
27+
db_user = "your_database_user"
28+
db_host = "localhost"
29+
db_password = "your_database_password"
30+
31+
# Instagram API (deprecated - Facebook killed the API)
32+
# instagram_client_id = "your_instagram_client_id"
33+
# instagram_access_token = "your_instagram_access_token"

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ dependencies = [
2121
"fuzzywuzzy>=0.18.0",
2222
"scrapy>=2.13.4",
2323
"pytest>=8.3.0",
24+
# Security notes:
25+
# - pip 25.2 vulnerability (GHSA-4xh5-x5gv-qwph): NOT AFFECTED - Python 3.12+ implements PEP 706
26+
# - scrapy 2.13.3 (PYSEC-2017-83): Already at latest version, old DoS vulnerability from 2017
2427
"termcolor>=2.4.0",
2528
"pycld2>=0.41",
2629
"polyglot>=16.7.4",
@@ -36,6 +39,9 @@ dependencies = [
3639
"webdriver-manager>=4.0.2",
3740
"scapy>=2.7.0",
3841
"matplotlib>=3.9.0",
42+
# Security: Pin vulnerable transitive dependencies to fixed versions
43+
"filelock>=3.20.2",
44+
"fonttools>=4.60.2",
3945
"iptcinfo3>=2.1.4",
4046
"requests>=2.31.0",
4147
"lxml>=5.2.0",

python-examples/hug-postgresql-example.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,46 @@
2020
@hug.get('/test')
2121
def test_connect():
2222
"""Test connection to db."""
23-
psycopg2.connect("dbname='t' user='t' host='localhost' password='test'")
23+
# Get database credentials from configs.py or environment variables
24+
try:
25+
from configs import db_name, db_user, db_host, db_password
26+
except ImportError:
27+
import os
28+
db_name = os.getenv('DB_NAME', 't')
29+
db_user = os.getenv('DB_USER', 't')
30+
db_host = os.getenv('DB_HOST', 'localhost')
31+
db_password = os.getenv('DB_PASSWORD', '')
32+
if not db_password:
33+
return {'error': 'Database password not configured. Set DB_PASSWORD environment variable or configs.py'}
34+
35+
psycopg2.connect(f"dbname='{db_name}' user='{db_user}' host='{db_host}' password='{db_password}'")
2436
return ('connected successfully to db! ready for queries.')
2537

2638

2739
@hug.get('/checktable')
2840
def test_write(user='t', table='testtable'):
2941
"""Test write to DB."""
30-
conn = psycopg2.connect("dbname='t' user='t' host='localhost' password='test'")
42+
# Get database credentials from configs.py or environment variables
43+
try:
44+
from configs import db_name, db_user, db_host, db_password
45+
except ImportError:
46+
import os
47+
db_name = os.getenv('DB_NAME', 't')
48+
db_user = os.getenv('DB_USER', 't')
49+
db_host = os.getenv('DB_HOST', 'localhost')
50+
db_password = os.getenv('DB_PASSWORD', '')
51+
if not db_password:
52+
return {'error': 'Database password not configured. Set DB_PASSWORD environment variable or configs.py'}
53+
54+
conn = psycopg2.connect(f"dbname='{db_name}' user='{db_user}' host='{db_host}' password='{db_password}'")
3155
print('connected successfully to db! ready for queries.')
3256
cur = conn.cursor()
33-
cur.execute("select exists(select relname from pg_class where relname='" + table + "')")
57+
# Fix SQL injection vulnerability by using parameterized queries
58+
cur.execute("SELECT exists(SELECT relname FROM pg_class WHERE relname=%s)", (table,))
3459
exists = cur.fetchone()[0]
3560
print(exists)
3661
cur.close()
62+
conn.close()
3763
if exists:
3864
return 'THIS TABLE EXISTS'
3965
else:

python-examples/instagram_geo-example.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,20 @@
1111
limiter = '1' # make sure to keep as string due to concat issues otherwise
1212
cityer = input('What city to search? (no spaces, include country): ')
1313
queryer = urllib.parse.quote(input('What is the name of venue to search?: '))
14-
clientider = '5HIGYBY4D24FXGCYTMYBUBGLYQSLORV03CRUS4E53F3GZ1VS'
15-
clientsecreter = 'B11MC3TFDEY10XQQTUDQGGTKDGCCJBOHD4RPY5VYEW12ZNIN'
14+
# Get API credentials from configs.py or environment variables
15+
try:
16+
from configs import foursquare_client_id, foursquare_client_secret
17+
clientider = foursquare_client_id
18+
clientsecreter = foursquare_client_secret
19+
except ImportError:
20+
import os
21+
clientider = os.getenv('FOURSQUARE_CLIENT_ID', '')
22+
clientsecreter = os.getenv('FOURSQUARE_CLIENT_SECRET', '')
23+
if not clientider or not clientsecreter:
24+
print('Error: Foursquare API credentials not found.')
25+
print('Please set FOURSQUARE_CLIENT_ID and FOURSQUARE_CLIENT_SECRET environment variables')
26+
print('or create configs.py with foursquare_client_id and foursquare_client_secret variables')
27+
exit(1)
1628
dater = dt.datetime.today().strftime("%Y%m%d") # the v needs YYYYMMDD format
1729
# the actual api call url
1830
foursquareapivenuesearch = f"https://api.foursquare.com/v2/venues/search?limit={limiter}&near={cityer}&query={queryer}&client_id={clientider}&client_secret={clientsecreter}&v={dater}"
@@ -28,6 +40,12 @@
2840
# INSTAGRAM API KILLED BY FACEBOOK - FUCK YOU FACEBOOK!
2941
print("This example was killed by Facebook killing API's. Complain to Facebook.")
3042
# globals Instagram API
31-
# instaclientid = '35b999a6d51344cc98ebb061da538999'
32-
# instaaccess_token='290277.35b999a.e2423222efa04c058b0e9b95cbf77c07'
43+
# Note: Instagram API credentials should be loaded from configs.py or environment variables
44+
# Example:
45+
# try:
46+
# from configs import instagram_client_id, instagram_access_token
47+
# except ImportError:
48+
# import os
49+
# instaclientid = os.getenv('INSTAGRAM_CLIENT_ID', '')
50+
# instaaccess_token = os.getenv('INSTAGRAM_ACCESS_TOKEN', '')
3351
#

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pypdf2>=3.0.1
2525
pinboard>=2.1.9
2626
webdriver-manager>=4.0.2
2727
scapy>=2.7.0
28+
filelock>=3.20.2
29+
fonttools>=4.60.2
2830
matplotlib>=3.9.0
2931
iptcinfo3>=2.1.4
3032
requests>=2.31.0

0 commit comments

Comments
 (0)