Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Ignore build artifacts
target/
dist/

# Ignore IDE and editor files
.vscode/
.idea/
*.swp
*.swo
*~

# Ignore OS-specific files
.DS_Store
Thumbs.db

# Ignore git files
.git/
.gitignore

# Note: Cargo.lock is included for reproducible builds

# Ignore temporary files
*.tmp
*.temp

# Ignore documentation build artifacts
book/

# Ignore CI/CD artifacts
.github/

# Ignore test artifacts
*.profraw

# Ignore local configuration
.env
.env.local

# Ignore cargo registry cache
.cargo/registry/
.cargo/git/

# Ignore benchmark results
criterion/

# Ignore log files
*.log

# Ignore backup files
*.bak
*.backup

# Ignore package files
*.tar.gz
*.zip
59 changes: 59 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Multi-stage build for safe-hash-rs
# Use the official Rust image as the build environment
FROM rust:1.83-slim-bookworm AS builder

# Set the working directory
WORKDIR /usr/src/app

# Install required build dependencies
RUN apt-get update && apt-get install -y \
pkg-config \
libssl-dev \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Copy the workspace files
COPY Cargo.toml Cargo.lock ./
COPY rust-toolchain.toml ./
COPY dist-workspace.toml ./
COPY rustfmt.toml ./

# Copy the source code
COPY crates/ ./crates/

# Build the application in release mode
RUN cargo build --release --bin safe-hash

# Runtime stage - use a minimal base image
FROM debian:bookworm-slim AS runtime

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
libssl3 \
&& rm -rf /var/lib/apt/lists/* \
&& update-ca-certificates

# Create a non-root user for security
RUN useradd --create-home --shell /bin/bash --user-group --uid 1000 safeuser

# Copy the binary from the builder stage
COPY --from=builder /usr/src/app/target/release/safe-hash /usr/local/bin/safe-hash

# Ensure the binary is executable
RUN chmod +x /usr/local/bin/safe-hash

# Create a directory for input files
RUN mkdir -p /app/input && chown -R safeuser:safeuser /app

# Switch to non-root user
USER safeuser

# Set the working directory
WORKDIR /app

# Set the entrypoint
ENTRYPOINT ["safe-hash"]

# Default command (show help)
CMD ["--help"]
81 changes: 79 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ A tool to verify Safe{Wallet} transaction data and EIP-712 messages before signi
# Security practices for using `safe-hash`

1. **Use a separate device for running this script**, totally different from what you use to send/sign your Safe{Wallet} transactions. This is to add some resilience in case your main device is compromised.
1. For extra security, run this inside a docker container or a secure operating system like Tails or Qubes OS.
1. For extra security, run this inside a docker container or a secure operating system like Tails or Qubes OS. **This project includes Podman/Docker support for enhanced security isolation.**
2. **Manually verify what you expect, and then compare to what you get**. This tool shows you what you get from you wallet based on your input, you should compare it to what you expect to get
3. **Understand the parameters you're signing**. This tool is useless if you don't know how to read the output! To get familiar, you can play the [wise-signer](https://wise-signer.cyfrin.io/) game to learn how calldata should be interpreted (with this tool too).
4. **Read/watch these resources**:
Expand Down Expand Up @@ -68,6 +68,78 @@ brew install cyfrin/tap/safe-hash
npm install -g @cyfrin/safe-hash
```

### Podman/Docker

For enhanced security, you can run `safe-hash` in a container using Podman or Docker. This provides additional isolation and is especially recommended when running on potentially compromised systems.

#### Quick Start with Podman

1. Build the container image:
```bash
./scripts/podman-build.sh
```

2. Run safe-hash in the container:
```bash
# Show help (note: use 'help' subcommand, not --help flag)
./scripts/safe-hash-rs help

# Verify a transaction
./scripts/safe-hash-rs tx --chain ethereum --nonce 63 --safe-address 0x1c694Fc3006D81ff4a56F97E1b99529066a23725 --safe-version 1.4.1

# Mount a directory to access local files
./scripts/safe-hash-rs -v ./test msg --chain sepolia --safe-address 0x657ff0D4eC65D82b2bC1247b0a558bcd2f80A0f1 --input-file /app/input/test_message.txt --safe-version 1.4.1
```

#### Manual Podman Commands

If you prefer to run commands manually:

```bash
# Build the image
podman build -t localhost/safe-hash:latest .

# Run with basic security
podman run --rm --cap-drop ALL --read-only --tmpfs /tmp --network host localhost/safe-hash:latest --help

# Mount files for processing
podman run --rm --cap-drop ALL --read-only --tmpfs /tmp --network host -v ./test:/app/input:ro,Z localhost/safe-hash:latest msg --chain sepolia --safe-address 0x657ff0D4eC65D82b2bC1247b0a558bcd2f80A0f1 --input-file /app/input/test_message.txt --safe-version 1.4.1
```

#### Docker Compatibility

The same Dockerfile works with Docker:

```bash
# Build with Docker
docker build -t safe-hash:latest .

# Run with Docker (basic help)
docker run --rm --cap-drop ALL --read-only --tmpfs /tmp --network host safe-hash:latest --help

# Mount files for processing with Docker
docker run --rm --cap-drop ALL --read-only --tmpfs /tmp --network host -v ./test:/app/input:ro safe-hash:latest msg --chain sepolia --safe-address 0x657ff0D4eC65D82b2bC1247b0a558bcd2f80A0f1 --input-file /app/input/test_message.txt --safe-version 1.4.1

The container setup includes several security enhancements:
- **Minimal base image**: Uses Debian slim for reduced attack surface
- **Non-root user**: Runs as unprivileged user inside container
- **Read-only filesystem**: Container filesystem is mounted read-only
- **Dropped capabilities**: All Linux capabilities are dropped
- **Network isolation**: Can be run with restricted networking
- **Resource limits**: Easily configurable resource constraints

#### Docker Compatibility

The same Dockerfile works with Docker:

```bash
# Build with Docker
docker build -t safe-hash:latest .

# Run with Docker
docker run --rm --cap-drop ALL --read-only --tmpfs /tmp --network host safe-hash:latest --help
```

# Usage

This tool helps protect against possible phishing or compromised UI attacks by allowing local verification of transaction and message hashes before signing.
Expand Down Expand Up @@ -176,10 +248,15 @@ Verify the above value as the Safe Tx Hash when signing the message from the led
## Trust Assumptions
* You trust this codebase
* You trust the Safe Wallet contracts
* You trust your OS
* You trust your OS (or container runtime when using Podman/Docker)
* You trust the [transaction service API](https://docs.safe.global/core-api/transaction-service-overview)
* Unless you use the `--offline` flag.

When using containers:
* You trust the container runtime (Podman/Docker)
* You trust the base container images (Rust and Debian)
* The container provides additional isolation but doesn't eliminate all trust assumptions

# Community-Maintained User Interface Implementations

> [!IMPORTANT]
Expand Down
Loading
Loading