GitHub Password Rotator
Boundaries
- Never pass GitHub passwords on the command line.
- Never print, store, commit, or summarize old passwords, new passwords, 2FA codes, cookies, or session tokens.
- Never print, store, commit, or summarize TOTP/2FA secrets from
2fa.fun.
- Use an isolated Chrome profile and the HTTP proxy for the whole browser flow. Default proxy:
http://127.0.0.1:11111.
- Treat 2FA, passkeys, CAPTCHA, unusual verification, and suspended-account pages as manual user steps.
- Do not claim the password changed unless the script reports completion or the user confirms success in the browser.
- For 2FA/passkey changes, use
--login-only; do not run the password-change flow and try to avoid the password form at runtime.
Standard Flow
For logging in to GitHub security settings without changing the password, use
--login-only. This keeps the isolated browser open after the helper reaches
https://github.com/settings/security:
read -rsp 'Current GitHub password: ' GITHUB_CURRENT_PASSWORD; echo
export GITHUB_CURRENT_PASSWORD
python3 skills/github-password-rotator/scripts/rotate_github_password.py \
--github-login username \
--login-only \
--manual-timeout-seconds 900
unset GITHUB_CURRENT_PASSWORD
Use this mode when the user wants to manually change 2FA, passkeys, recovery
methods, or other security settings. The helper only logs in, handles sudo
password confirmation when detected, and stops before any password-change form.
Use environment variables or hidden TTY prompts for both passwords:
read -rsp 'Current GitHub password: ' GITHUB_CURRENT_PASSWORD; echo
read -rsp 'New GitHub password: ' GITHUB_NEW_PASSWORD; echo
read -rsp 'GitHub TOTP secret for 2fa.fun: ' GITHUB_TOTP_SECRET; echo
export GITHUB_CURRENT_PASSWORD GITHUB_NEW_PASSWORD GITHUB_TOTP_SECRET
python3 skills/github-password-rotator/scripts/rotate_github_password.py \
--github-login username \
--manual-timeout-seconds 900 \
--auto-2fa-fun \
--create-learning-repo
unset GITHUB_CURRENT_PASSWORD GITHUB_NEW_PASSWORD GITHUB_TOTP_SECRET
The helper:
- Opens
https://github.com/settings/security in an isolated Chrome profile through the proxy.
- Fills the GitHub login page with
--github-login and the current password.
- If
--auto-2fa-fun is set and GitHub shows an app-code 2FA prompt, opens or reuses https://2fa.fun/, enters the TOTP secret, reads the generated code from input.faotp.value, and submits it to GitHub without printing the code.
- Waits for the user to complete passkey, device verification, CAPTCHA, suspended-account inspection, or any 2FA step that cannot be handled from
2fa.fun.
- Handles GitHub sudo password confirmation with the current password when detected.
- Fills the password-change form with current password, new password, and confirmation.
- Exits successfully after GitHub reports success, or after a submitted password form collapses back to the
Change password state without an explicit success message.
- Navigates back to
https://github.com/settings/security after a completed submit so browser refresh will not resubmit the password form.
- When
--create-learning-repo is set, waits a random 3-10 seconds after the password change before creating the repository, then creates hello-world-from-<account-slug> and writes a beginner-friendly English README.md.
Useful Options
--github-login USER: required GitHub username or email.
--current-password-env NAME: defaults to GITHUB_CURRENT_PASSWORD.
--new-password-env NAME: defaults to GITHUB_NEW_PASSWORD.
--totp-secret-env NAME: defaults to GITHUB_TOTP_SECRET; only read when --auto-2fa-fun is set.
--proxy http://127.0.0.1:11111: override login proxy.
--settings-url URL: override GitHub password settings URL.
--manual-timeout-seconds 900: time allowed for manual verification.
--keep-browser: keep the isolated browser open after the helper exits.
--login-only: log in to GitHub security settings without reading a new password or submitting the password-change form; implies --keep-browser.
--auto-2fa-fun: use the hidden TOTP secret with 2fa.fun to fill GitHub app-code 2FA prompts.
--create-learning-repo: after password rotation, create a public beginner learning repository named hello-world-from-<github-login-slug>.
--dry-run: print redacted plan and verify script wiring without launching a browser or requiring passwords.
Learning Repository
- Repository name is deterministic:
hello-world-from-<account-slug>, where the slug lowercases the GitHub login and replaces non-alphanumeric runs with -.
- README content must be English, beginner-oriented, and generated from multiple randomized sections at runtime. Do not make it a fixed template keyed only by account name.
- The README should still include the account name in the heading so the repository looks account-specific.
- If GitHub reports the repository already exists or the editor cannot be found, stop with a clear failure instead of silently skipping the repository.
Failure Handling
- If GitHub shows a suspended/disabled account page, stop the script and record the account in the appeal tracker instead of retrying.
- If the helper times out while GitHub is logged in, inspect the visible browser. Do not scrape or print cookies/tokens.
- If
2fa.fun is used, read generated codes only from input.faotp.value; do not parse arbitrary page text or secret fields as codes.
- If GitHub changed the settings DOM, rerun with
--keep-browser, inspect visible labels/selectors, then patch drive_github_password_change.mjs.
- GitHub may not show a password success flash. After a submit, treat the collapsed password form plus visible
Change password entry as a completed no-flash state, then force a GET navigation back to the settings URL to avoid refresh resubmission.
- If the password-change form remains visible after submit, do not assume success. Check visible validation text or ask the user to confirm.
Verification
Dry-run and syntax checks are safe:
python3 skills/github-password-rotator/scripts/rotate_github_password.py \
--github-login username \
--login-only \
--dry-run
python3 -m py_compile skills/github-password-rotator/scripts/rotate_github_password.py
node --check skills/github-password-rotator/scripts/drive_github_password_change.mjs
For live verification, rely on GitHub's success page, the completed no-flash
collapsed form state, a login_completed status for --login-only, or a
user-confirmed successful login with the new password. Do not log the password
itself.
1---2name: github-password-rotator3description: Rotates GitHub account passwords and logs into security settings using an isolated browser, with manual 2FA handling and optional TOTP automation.4---56# GitHub Password Rotator78## Boundaries910- Never pass GitHub passwords on the command line.11- Never print, store, commit, or summarize old passwords, new passwords, 2FA codes, cookies, or session tokens.12- Never print, store, commit, or summarize TOTP/2FA secrets from `2fa.fun`.13- Use an isolated Chrome profile and the HTTP proxy for the whole browser flow. Default proxy: `http://127.0.0.1:11111`.14- Treat 2FA, passkeys, CAPTCHA, unusual verification, and suspended-account pages as manual user steps.15- Do not claim the password changed unless the script reports completion or the user confirms success in the browser.16- For 2FA/passkey changes, use `--login-only`; do not run the password-change flow and try to avoid the password form at runtime.1718## Standard Flow1920For logging in to GitHub security settings without changing the password, use21`--login-only`. This keeps the isolated browser open after the helper reaches22`https://github.com/settings/security`:2324```bash25read -rsp 'Current GitHub password: ' GITHUB_CURRENT_PASSWORD; echo26export GITHUB_CURRENT_PASSWORD27python3 skills/github-password-rotator/scripts/rotate_github_password.py \28 --github-login username \29 --login-only \30 --manual-timeout-seconds 90031unset GITHUB_CURRENT_PASSWORD32```3334Use this mode when the user wants to manually change 2FA, passkeys, recovery35methods, or other security settings. The helper only logs in, handles sudo36password confirmation when detected, and stops before any password-change form.3738Use environment variables or hidden TTY prompts for both passwords:3940```bash41read -rsp 'Current GitHub password: ' GITHUB_CURRENT_PASSWORD; echo42read -rsp 'New GitHub password: ' GITHUB_NEW_PASSWORD; echo43read -rsp 'GitHub TOTP secret for 2fa.fun: ' GITHUB_TOTP_SECRET; echo44export GITHUB_CURRENT_PASSWORD GITHUB_NEW_PASSWORD GITHUB_TOTP_SECRET45python3 skills/github-password-rotator/scripts/rotate_github_password.py \46 --github-login username \47 --manual-timeout-seconds 900 \48 --auto-2fa-fun \49 --create-learning-repo50unset GITHUB_CURRENT_PASSWORD GITHUB_NEW_PASSWORD GITHUB_TOTP_SECRET51```5253The helper:54551. Opens `https://github.com/settings/security` in an isolated Chrome profile through the proxy.562. Fills the GitHub login page with `--github-login` and the current password.573. If `--auto-2fa-fun` is set and GitHub shows an app-code 2FA prompt, opens or reuses `https://2fa.fun/`, enters the TOTP secret, reads the generated code from `input.faotp.value`, and submits it to GitHub without printing the code.584. Waits for the user to complete passkey, device verification, CAPTCHA, suspended-account inspection, or any 2FA step that cannot be handled from `2fa.fun`.595. Handles GitHub sudo password confirmation with the current password when detected.606. Fills the password-change form with current password, new password, and confirmation.617. Exits successfully after GitHub reports success, or after a submitted password form collapses back to the `Change password` state without an explicit success message.628. Navigates back to `https://github.com/settings/security` after a completed submit so browser refresh will not resubmit the password form.639. When `--create-learning-repo` is set, waits a random 3-10 seconds after the password change before creating the repository, then creates `hello-world-from-<account-slug>` and writes a beginner-friendly English `README.md`.6465## Useful Options6667- `--github-login USER`: required GitHub username or email.68- `--current-password-env NAME`: defaults to `GITHUB_CURRENT_PASSWORD`.69- `--new-password-env NAME`: defaults to `GITHUB_NEW_PASSWORD`.70- `--totp-secret-env NAME`: defaults to `GITHUB_TOTP_SECRET`; only read when `--auto-2fa-fun` is set.71- `--proxy http://127.0.0.1:11111`: override login proxy.72- `--settings-url URL`: override GitHub password settings URL.73- `--manual-timeout-seconds 900`: time allowed for manual verification.74- `--keep-browser`: keep the isolated browser open after the helper exits.75- `--login-only`: log in to GitHub security settings without reading a new password or submitting the password-change form; implies `--keep-browser`.76- `--auto-2fa-fun`: use the hidden TOTP secret with `2fa.fun` to fill GitHub app-code 2FA prompts.77- `--create-learning-repo`: after password rotation, create a public beginner learning repository named `hello-world-from-<github-login-slug>`.78- `--dry-run`: print redacted plan and verify script wiring without launching a browser or requiring passwords.7980## Learning Repository8182- Repository name is deterministic: `hello-world-from-<account-slug>`, where the slug lowercases the GitHub login and replaces non-alphanumeric runs with `-`.83- README content must be English, beginner-oriented, and generated from multiple randomized sections at runtime. Do not make it a fixed template keyed only by account name.84- The README should still include the account name in the heading so the repository looks account-specific.85- If GitHub reports the repository already exists or the editor cannot be found, stop with a clear failure instead of silently skipping the repository.8687## Failure Handling8889- If GitHub shows a suspended/disabled account page, stop the script and record the account in the appeal tracker instead of retrying.90- If the helper times out while GitHub is logged in, inspect the visible browser. Do not scrape or print cookies/tokens.91- If `2fa.fun` is used, read generated codes only from `input.faotp.value`; do not parse arbitrary page text or secret fields as codes.92- If GitHub changed the settings DOM, rerun with `--keep-browser`, inspect visible labels/selectors, then patch `drive_github_password_change.mjs`.93- GitHub may not show a password success flash. After a submit, treat the collapsed password form plus visible `Change password` entry as a completed no-flash state, then force a GET navigation back to the settings URL to avoid refresh resubmission.94- If the password-change form remains visible after submit, do not assume success. Check visible validation text or ask the user to confirm.9596## Verification9798Dry-run and syntax checks are safe:99100```bash101python3 skills/github-password-rotator/scripts/rotate_github_password.py \102 --github-login username \103 --login-only \104 --dry-run105106python3 -m py_compile skills/github-password-rotator/scripts/rotate_github_password.py107node --check skills/github-password-rotator/scripts/drive_github_password_change.mjs108```109110For live verification, rely on GitHub's success page, the completed no-flash111collapsed form state, a `login_completed` status for `--login-only`, or a112user-confirmed successful login with the new password. Do not log the password113itself.