-
Notifications
You must be signed in to change notification settings - Fork 168
docs: add Stellar-specific security considerations to SECURITY.md (#812) #825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -61,4 +61,48 @@ connect-src 'self' https://rpc-futurenet.stellar.org | |
|
|
||
| Implementation: `frontend/vite.config.ts` (`content-security-policy` plugin and dev/preview headers). | ||
|
|
||
|
|
||
| ## Stellar-Specific Security Considerations | ||
|
|
||
| ### Testnet vs Mainnet Safety Checklist | ||
|
|
||
| Before deploying or interacting with contracts, confirm which network you're targeting: | ||
|
|
||
| - [ ] Verify `NETWORK_PASSPHRASE` matches the intended network (Testnet: `Test SDF Network ; September 2015`, Mainnet: `Public Global Stellar Network ; September 2015`). | ||
| - [ ] Confirm the Horizon/RPC endpoint URL points to the correct network before signing transactions. | ||
| - [ ] Never reuse Testnet keypairs for Mainnet accounts — treat them as fully separate identities. | ||
| - [ ] Double-check contract IDs; a valid contract ID on Testnet has no relationship to the same ID on Mainnet. | ||
| - [ ] Use a wallet or signer that clearly displays which network is active before every transaction approval. | ||
| - [ ] Run integration tests exclusively against Testnet/Futurenet; never point CI against Mainnet. | ||
|
|
||
| ### Private Key Management Best Practices | ||
|
|
||
| - **Never commit secret keys** (`S...` seed values) to source control, `.env` files tracked by git, or CI logs. | ||
| - Store signing keys in a hardware wallet (e.g., Ledger) or OS-level secure storage for any Mainnet operations. | ||
| - Use multi-signature (multisig) setups for contract admin/upgrade keys rather than a single signer. | ||
| - Rotate deployment/admin keys if there's any suspicion of exposure, and prefer short-lived keys for CI/CD automation over long-lived ones. | ||
| - For frontend apps, never request or handle raw secret keys — rely on wallet-based signing (Freighter, xBull, etc.) so keys never touch application code. | ||
| - Environment variables holding sensitive keys should be scoped narrowly (per-environment) and excluded via `.gitignore`. | ||
|
Comment on lines
+81
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win Separate persistent upgrade authority from CI signing keys. Clarify that short-lived CI/CD signers must not be the contract’s durable admin/upgrade authority. The latter should remain behind the protected multisig/governance process described above, with rotation performed through an explicit controlled migration. 🤖 Prompt for AI AgentsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
rg -n --hidden -g '!.git' \
'(process\.env|import\.meta\.env|os\.environ|getenv|NETWORK_PASSPHRASE|SECRET|PRIVATE|SEED|KEY|TOKEN)'Repository: ritik4ever/stellar-stream Length of output: 163 🏁 Script executed: #!/bin/bash
set -eu
echo "## SECURITY.md around target line"
if [ -f SECURITY.md ]; then
wc -l SECURITY.md
sed -n '1,130p' SECURITY.md | nl -ba | sed -n '60,95p'
else
echo "SECURITY.md not found"
fi
echo
echo "## Relevant env/API/security references in repo"
rg -n \
-g '!/.git' \
'(process\.env|import\.meta\.env|os\.environ|getenv\(|NETWORK_PASSPHRASE|PASSPHRASE|SECRET|PRIVATE|SEED|KEY|TOKEN|API_KEY|API_SECRET|ENVS?|dotenv|dotenv-expand)' \
. || true
echo
echo "## README/config/env-like filenames"
fd -t f '^(README|SECURITY|env|.*env.*|.*config.*|.*secret.*|.*token.*|.*key.*)' . | sed -n '1,200p'Repository: ritik4ever/stellar-stream Length of output: 50382 🏁 Script executed: #!/bin/bash
set -eu
echo "## SECURITY.md lines 70-88"
sed -n '70,88p' SECURITY.md
echo
echo "## .env/.env.* / config-like secrets references, excluding generated frontend reports"
rg -n \
-g '!frontend/playwright-report' -g '!*.ts.snap' -g '!*.css' -g '!*.js' -g '!*.jsx' -g '!*.tsx' \
'\.env|VITE_.*SECRET|VITE_.*PRIVATE|VITE_.*TOKEN|VITE_.*KEY|VITE_.*SIGNING|JWT_SECRET|SERVER_PRIVATE_KEY|SECRET_KEY|WEBHOOK_SIGNING_SECRET|NETWORK_PASSPHRASE|CONTRACT_ID' \
. || true
echo
echo "## Read-only semantic probe: .gitignore controls untracked files only"
python3 - <<'PY'
from pathlib import Path
import subprocess
tmp = subprocess.check_output(["mktemp", "-d"], text=True).strip()
repo = Path(tmp) / "repo"
repo.mkdir()
(repo / ".git").mkdir()
(repo / ".gitignore").write_text(".env\n")
(repo / "tracked.txt").write_text("tracked")
(repo / ".env").write_text("SECRET=in_file")
(repo / "directory/.env").mkdir(parents=True)
(repo / "directory/.env").write_text("SECRET=in_directory")
patterns = [
("file .env untracked", str(repo / ".env")),
("directory .env untracked", str(repo / "directory/.env")),
("untracked sibling", str(repo / "secret.txt")),
]
for description, path in patterns:
out = subprocess.check_output(
["git", "-C", str(repo), "check-ignore", "-v", path],
stderr=subprocess.DEVNULL, text=True, check=False
)
print(f"{description}: {'ignored by gitignore' if out.strip() else 'not ignored by gitignore'}")
tracked = repo / "tracked.txt"
tracked.write_text("")
out = subprocess.check_output(
["git", "-C", str(repo), "check-ignore", "-v", str(tracked)],
stderr=subprocess.DEVNULL, text=True, check=False
)
print(f"tracked.txt: {'ignored by gitignore' if out.strip() else 'not ignored by gitignore'}")
PYRepository: ritik4ever/stellar-stream Length of output: 40975 Replace
🤖 Prompt for AI Agents |
||
|
|
||
| ### Contract Upgrade Security Considerations | ||
|
|
||
| - Restrict upgrade authority to a multisig or governance-controlled address — never a single EOA-equivalent signer. | ||
| - Emit an event on every upgrade so upgrades are auditable on-chain. | ||
| - Consider a timelock between proposing and executing an upgrade, giving users/auditors time to react. | ||
| - Validate that new WASM hashes are reviewed and, where possible, verified against a reproducible build before upgrade execution. | ||
| - Ensure upgraded contracts preserve storage layout compatibility to avoid state corruption. | ||
| - Document and test a rollback plan in case an upgrade introduces a critical bug. | ||
|
|
||
| ### Oracle Manipulation Attack Vectors and Mitigations | ||
|
|
||
| **Attack vectors:** | ||
| - **Price manipulation via low liquidity**: An attacker manipulates a thinly-traded pair to distort a price feed the contract relies on. | ||
| - **Flash-loan-assisted manipulation**: Large, short-term capital is used to skew an on-chain price within a single transaction/block. | ||
| - **Stale data reliance**: Contract logic uses outdated oracle data because it doesn't check the data's freshness/timestamp. | ||
|
Comment on lines
+98
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "SECURITY.md relevant section:"
sed -n '1,140p' SECURITY.md | nl -ba | sed -n '80,110p'
echo
echo "Search for Stellar ledger/block terminology:"
rg -n "block|ledger|flash" SECURITY.md || true
echo
echo "Repository files (top-level, relevant docs):"
git ls-files | sed -n '1,120p'Repository: ritik4ever/stellar-stream Length of output: 233 🌐 Web query:
💡 Result: In the Stellar network, the term "ledger" serves a distinct purpose compared to the "block" terminology used in many other blockchain architectures [1][2]. A Stellar ledger represents the state of the entire network at a specific point in time [1][3]. It contains the complete set of all accounts, balances, smart contract data, and other persistent information at that moment [1][4][5]. In contrast, traditional blockchain "blocks" are typically viewed as individual units of data that store a collection of transactions, which are then linked to form a history [1]. While Stellar does not use "blocks" in the conventional sense to describe its primary state unit, it functions as a blockchain [1]. The network reaches consensus via the Stellar Consensus Protocol (SCP) to apply a set of transactions to the previous ledger, resulting in a new "last closed ledger" [1][3]. Each ledger is cryptographically linked to the previous one, creating an unbroken historical chain that functions analogously to a blockchain [1][6]. Key distinctions and technical nuances include: - State vs. Transactions: A Stellar ledger captures the current state of the entire network, whereas many other blockchains focus on the block as a container for transactions [1][7]. - Terminology Usage: While official documentation centers on "ledger," the term can sometimes contextually refer to either the individual state snapshot (the equivalent of a block) or the entire record of network history [1][2]. - History Archives: In infrastructure and archival contexts, Stellar documentation may still occasionally reference "blocks" when discussing the storage of compressed transaction logs in history archives, though "ledger" remains the standard term for the consensus unit [8]. In summary, Stellar uses ledgers as the atomic units of state consensus, which perform the same functional role as blocks in other blockchain systems [1][9]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "SECURITY.md relevant section:"
sed -n '80,110p' SECURITY.md | awk '{printf "%4d %s\n", NR+79, $0}'
echo
echo "Security doc references to block/ledger/flash:"
grep -n -i 'block\|ledger\|flash' SECURITY.md || true
echo
echo "Repository files (top-level, relevant docs):"
git ls-files | sed -n '1,160p'Repository: ritik4ever/stellar-stream Length of output: 9074 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "SECURITY.md top relevant section header/lines 86-95:"
sed -n '86,96p' SECURITY.md | awk '{printf "%4d %s\n", NR+85, $0}'Repository: ritik4ever/stellar-stream Length of output: 978 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '95,100p' SECURITY.md | awk '{printf "%4d %s\n", NR+94, $0}'Repository: ritik4ever/stellar-stream Length of output: 672 Use Stellar ledger terminology and qualify flash-loan attacks. Line 99 still says 🤖 Prompt for AI Agents |
||
| - **Single-source dependency**: Relying on one oracle/price feed creates a single point of failure. | ||
|
|
||
| **Mitigations:** | ||
| - Use decentralized, multi-source oracle aggregation rather than a single feed. | ||
| - Enforce staleness checks — reject oracle data older than a defined threshold. | ||
| - Apply circuit breakers or maximum deviation checks: reject price updates that swing beyond a sane percentage in a short window. | ||
| - Prefer time-weighted average price (TWAP) over spot price for any calculation vulnerable to short-term manipulation. | ||
| - Cross-validate critical price data against a secondary source before executing high-value operations. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: ritik4ever/stellar-stream
Length of output: 3328
🌐 Web query:
Stellar Futurenet network passphrase Test SDF Future Network October 2022💡 Result:
The network passphrase for the Stellar Futurenet is "Test SDF Future Network; October 2022" [1][2][3]. This passphrase is a unique identifier used by the Stellar network to ensure transaction validity across different environments [1][4][5]. By including the network passphrase in the signature process, Stellar prevents transaction replay attacks, where a valid transaction on one network could otherwise be improperly broadcast or executed on another [5]. Developers typically use this passphrase when configuring their Stellar SDKs or tools to interact specifically with the Futurenet, which serves as a testing environment for bleeding-edge features [1][6]. If an incorrect passphrase is provided when signing a transaction, the transaction will be rejected by the network nodes [6][5].
Citations:
Include Futurenet in the network-passphrase checklist.
This section allows CI against Futurenet, but the passphrase list currently only covers Testnet and Mainnet. Add
Test SDF Future Network ; October 2022, or explicitly scope the checklist to Testnet/Mainnet.🤖 Prompt for AI Agents