python
28 lines · 6 steps
Safely compressing and extracting tar.gz archives
Two helpers that bundle a directory into a gzip tarball and unpack it while guarding against path-traversal attacks.
Explained by
highlit
1import os
2import tarfile
3from pathlib import Path
4
5
6def compress_directory(source_dir, archive_path):
7 source = Path(source_dir).resolve()
8 if not source.is_dir():
9 raise NotADirectoryError(f"{source} is not a directory")
10
11 with tarfile.open(archive_path, "w:gz") as tar:
12 tar.add(source, arcname=source.name)
13
14 return Path(archive_path).resolve()
15
16
17def decompress_archive(archive_path, dest_dir):
18 dest = Path(dest_dir).resolve()
19 dest.mkdir(parents=True, exist_ok=True)
20
21 with tarfile.open(archive_path, "r:gz") as tar:
22 for member in tar.getmembers():
23 target = (dest / member.name).resolve()
24 if not str(target).startswith(str(dest) + os.sep):
25 raise ValueError(f"Unsafe path in archive: {member.name}")
26 tar.extractall(dest)
27
28 return dest
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Resolving paths to absolute form early makes validation and comparisons reliable.
- 2Never trust archive member names — extracting them blindly enables path-traversal writes outside your target.
- 3Checking each resolved target stays under the destination prefix neutralizes malicious archive entries before extraction.
Related explainers
python
from flask import Blueprint, jsonify, request, abort v1 = Blueprint("users_v1", __name__) v2 = Blueprint("users_v2", __name__)
Versioning a Flask API with Blueprints
api versioning
blueprints
rest
Intermediate
7 steps
python
import time import threading from enum import Enum from functools import wraps
Building a circuit breaker in Python
circuit-breaker
resilience
decorators
Advanced
7 steps
go
package auth import ( "net/http"
Setting and reading secure session cookies in Go
cookies
session-management
security
Intermediate
6 steps
python
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector from django.core.cache import cache from django.db.models import F from django.http import JsonResponse
Ranked full-text search in Django
full-text-search
debouncing
caching
Advanced
9 steps
python
import os from datetime import timedelta
Class-based config in a Flask app factory
configuration
app-factory
inheritance
Intermediate
7 steps
python
import time from flask import Flask, g, request
Timing requests with Flask hooks
middleware
request-lifecycle
instrumentation
Intermediate
5 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/safely-compressing-and-extracting-tar-gz-archives-explained-python-7786/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.