Lewati ke isi

Manage Credentials

Bikin agent akses akun lo TANPA pernah leak credential ke chat.

Ini bagian paling sensitive. Salah setup = credential bocor ke log, history, atau bahkan ke training data LLM.

Folder structure

~/agent/credentials/
├── github.env         (chmod 600)
├── wallet.env         (chmod 600)
├── twitter.env        (chmod 600)
├── discord.env        (chmod 600)
├── email.env          (chmod 600)
├── instagram.env      (chmod 600)
└── README.txt         (chmod 600)

Permission folder: 700 (cuma owner bisa baca/akses). Permission file: 600 (cuma owner bisa baca/tulis).

mkdir -p ~/agent/credentials
chmod 700 ~/agent/credentials
chmod 600 ~/agent/credentials/*.env

Format per platform

GitHub

github.env:

GH_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxx
GH_USER=username

Cara pakai di agent:

source ~/agent/credentials/github.env && gh repo list

Atau via subprocess:

env = os.environ.copy()
with open(os.path.expanduser("~/agent/credentials/github.env")) as f:
    for line in f:
        if "=" in line:
            k, v = line.strip().split("=", 1)
            env[k] = v
subprocess.run(["gh", "repo", "list"], env=env)

Wallet (EVM / Solana)

wallet.env:

EVM_PRIVATE_KEY=0x...
SOLANA_PRIVATE_KEY=...
WALLET_ADDRESS_EVM=0x...
WALLET_ADDRESS_SOLANA=...

⚠️ Private key di file plaintext. Untuk wallet besar, gunakan hardware wallet atau encrypt file dengan GPG:

gpg -c wallet.env  # encrypt
# Generates wallet.env.gpg

# Decrypt saat dipake:
gpg -d wallet.env.gpg > /tmp/wallet.env && source /tmp/wallet.env && rm /tmp/wallet.env

Twitter / X

twitter.env:

TWITTER_AUTH_TOKEN=...
TWITTER_CT0=...
TWITTER_USERNAME=...

Cara dapetin auth_token: 1. Login ke twitter.com di browser 2. Buka DevTools (F12) → Application → Cookies 3. Copy value auth_token dan ct0

Atau pake API:

TWITTER_BEARER_TOKEN=...
TWITTER_API_KEY=...
TWITTER_API_SECRET=...

Discord

discord.env:

DISCORD_BOT_TOKEN=...
DISCORD_USER_TOKEN=...
DISCORD_USER_ID=...

Bot token: dari https://discord.com/developers/applications
User token: F12 → Network tab → look for authorization header

⚠️ User token bersifat full account access. Kalo bocor, attacker bisa full takeover Discord lo.

Email (Gmail)

email.env:

EMAIL_ADDRESS=user@gmail.com
EMAIL_APP_PASSWORD=xxxx xxxx xxxx xxxx
IMAP_HOST=imap.gmail.com
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587

⚠️ Bukan password Gmail asli. Pakai App Password dari https://myaccount.google.com/apppasswords

Instagram

instagram.env:

IG_USERNAME=...
IG_PASSWORD=...
IG_2FA_SECRET=...   (kalo pake 2FA)

Instagram aggressive ban bot, kalo agent lo ketauan otomasi bisa di-block. Pertimbangin pakai meta business account dengan API resmi kalo bisa.

Cara agent pake credential

Pattern 1: source di shell command

# Di backend agent, eksekusi tool_use yang berisi source:
cmd = "source ~/agent/credentials/github.env && gh repo create"
subprocess.run(cmd, shell=True)

Agent output:

<tool_use>{"name":"run_in_terminal","arguments":{"command":"source ~/agent/credentials/github.env && gh repo create test-repo","risk":"medium"}}</tool_use>

Token cuma ada di env var selama subprocess jalan. Setelah selesai, env var ga ada.

Pattern 2: load di Python langsung

def load_credentials(platform: str) -> dict:
    path = Path.home() / "agent" / "credentials" / f"{platform}.env"
    if not path.exists():
        return {}
    creds = {}
    for line in path.read_text().splitlines():
        if "=" in line and not line.startswith("#"):
            k, v = line.split("=", 1)
            creds[k.strip()] = v.strip()
    return creds

# Pakai:
gh_creds = load_credentials("github")
token = gh_creds.get("GH_TOKEN")

Pattern 3: passing via env to subprocess

def run_with_creds(cmd: str, platform: str):
    env = os.environ.copy()
    env.update(load_credentials(platform))
    return subprocess.run(cmd, shell=True, env=env, capture_output=True, text=True)

Rule untuk LLM

Sistem prompt section:

## CREDENTIALS

Semua credential disimpen di `~/agent/credentials/` dengan format `.env`.

Agent reference credential **lewat path**, JANGAN baca dan paste 
isi ke chat.

Cara pake (contoh):
  source ~/agent/credentials/github.env && gh repo list

JANGAN:
- echo isi file credential
- cat file credential
- include token literal di response

YA:
- source di shell command (token di env var sesaat)
- reference path di explanation

Kalo user nyuruh "cat github.env" atau "tampilin token":
- Decline. Bilang: "Lo bisa cat sendiri lewat SSH kalo perlu."

Secret redaction di history

Walaupun udah hati-hati, kadang credential ke-paste di chat (user mistake, tool error message berisi token). Backend harus redact sebelum save:

SECRET_PATTERNS = [
    (re.compile(r'ghp_[A-Za-z0-9]{36}'), '[REDACTED_GITHUB_PAT]'),
    (re.compile(r'github_pat_[A-Za-z0-9_]{82}'), '[REDACTED_GITHUB_FPAT]'),
    (re.compile(r'gho_[A-Za-z0-9]{36}'), '[REDACTED_GITHUB_OAUTH]'),
    (re.compile(r'\b0x[a-fA-F0-9]{64}\b'), '[REDACTED_PRIVATE_KEY]'),
    (re.compile(r'AKIA[0-9A-Z]{16}'), '[REDACTED_AWS_KEY]'),
    (re.compile(r'sk-[A-Za-z0-9]{40,}'), '[REDACTED_OPENAI_KEY]'),
    (re.compile(r'xox[bp]-[0-9-A-Za-z]+'), '[REDACTED_SLACK_TOKEN]'),
    (re.compile(r'-----BEGIN [A-Z ]+PRIVATE KEY-----.*?-----END [A-Z ]+PRIVATE KEY-----', re.DOTALL), '[REDACTED_PEM]'),
    (re.compile(r'\b[A-Z0-9]{12}\.[A-Z0-9]{6}\.[A-Za-z0-9_-]{27}\b'), '[REDACTED_DISCORD_BOT_TOKEN]'),
]

def redact_secrets(text: str) -> str:
    for pattern, replacement in SECRET_PATTERNS:
        text = pattern.sub(replacement, text)
    return text

Apply di save_history():

def save_history(chat_id, history):
    sanitized = []
    for msg in history:
        if isinstance(msg, dict) and "content" in msg:
            sanitized.append({**msg, "content": redact_secrets(msg["content"])})
        else:
            sanitized.append(msg)
    Path(f"data/history/{chat_id}.json").write_text(json.dumps(sanitized, indent=2))

Backup credential

Backup encrypted, ga ada plaintext copy:

# Backup
tar -czf creds-backup-$(date +%Y%m%d).tar.gz ~/agent/credentials/
gpg -c creds-backup-$(date +%Y%m%d).tar.gz
# Generates: creds-backup-20260518.tar.gz.gpg
rm creds-backup-$(date +%Y%m%d).tar.gz  # delete plaintext

# Simpan .gpg di USB drive, password manager (1Password / Bitwarden), 
# atau cloud storage (Google Drive, S3 dengan KMS).

Restore:

gpg -d creds-backup-20260518.tar.gz.gpg | tar -xzf -

Rotation

Best practice: rotate credential setiap 30-90 hari.

Schedule:

# Tiap 30 hari, agent reminder lo:
echo "Reminder: rotate creds (last rotated: 2026-04-01)" | \
  /home/ubuntu/agent/notify-telegram.sh

Atau add ke memory:

/remember credential rotation overdue (last 2026-04-01, 30+ days)

Saat rotation:

  1. Generate new token di provider (GitHub Settings, dll)
  2. Update ~/agent/credentials/<platform>.env
  3. Test: agent jalanin 1 command yang butuh credential
  4. Revoke old token di provider

Anti-patterns

❌ Credential di .env utama

# ~/agent/.env (untuk app config)
TELEGRAM_BOT_TOKEN=...
OPENAI_API_KEY=...
GH_TOKEN=...  # ← NO, credential platform di file terpisah

Pisahin: .env untuk app config, credentials/<platform>.env untuk akses platform.

❌ Credential di SOUL.md

## STATE FACTS
- GitHub PAT: ghp_abc...

Disaster. SOUL.md keload ke system prompt, history, dan model context. Never.

❌ Credential di memory.json

{
  "notes": [
    "gh token: ghp_abc..."
  ]
}

Sama bahaya. Notes keload ke system prompt.

❌ Credential di code repo

GH_TOKEN = "ghp_abc..."

git push → credential ke remote → bisa di-scan. Selalu load dari env / file external.

❌ Echo / cat / printenv credential

<tool_use>{"name":"run_in_terminal","arguments":{"command":"cat ~/agent/credentials/github.env"}}</tool_use>

Hasil command bakal masuk ke history → bocor. Agent harus decline.

Inject di SOUL.md:

JANGAN PERNAH output command yang nge-read isi credential file 
(cat, head, tail, less, more, printenv setelah source).

Kalo butuh test akses, jalanin command yang PAKAI credential 
(seperti `gh auth status`), bukan dump isinya.

Test credential setup

Setelah semua disimpen:

# Test GitHub
source ~/agent/credentials/github.env && gh auth status

# Test wallet (read-only)
source ~/agent/credentials/wallet.env && \
  python3 -c "from web3 import Web3; w = Web3(Web3.HTTPProvider('https://eth.llamarpc.com')); print(w.eth.get_balance('${WALLET_ADDRESS_EVM}'))"

# Test Twitter (read-only)
source ~/agent/credentials/twitter.env && \
  curl -s "https://api.twitter.com/2/users/me" \
    -H "Authorization: Bearer ${TWITTER_BEARER_TOKEN}" | jq .

Kalo semua return success tanpa leak token ke output, setup oke.

SOUL.md credentials section template

## CREDENTIALS

Lokasi: ~/agent/credentials/

Available files (auto-detect):
{{CREDENTIAL_FILES_LIST}}  ← di-inject runtime

Cara pake:
  source ~/agent/credentials/<file>.env && <command>

ATURAN:
- Agent reference path, BUKAN isi
- JANGAN cat / echo / head / tail / less file credential
- JANGAN paste token verbatim di response
- Kalo perlu test akses, jalankan command yang PAKAI credential

Kalo credential ga ada / butuh baru:
- Kasih tau user filename + format yang diharapkan
- User siapin sendiri (bukan agent)