Install
$ agentstack add skill-joslat-maf-doctor-maf-anti-pattern-scanner ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
maf-anti-pattern-scanner
The migration tooling answers "is this code on MAF 1.3.0?" This skill answers a different question: "is this MAF 1.3.0 code following best practices?" Same codebase, different lens.
When to use
- After a migration plan finishes — verify the converted code isn't merely compiling, it's idiomatic.
- On any clean 1.3.0 codebase as a periodic audit.
- In CI on PRs touching MAF agent/workflow code, scoped to the diff.
When NOT to use
- For migration discovery — that's
maf-obsolete-api-registry+cs0618-hunter. This skill assumes you're already on 1.3.0. - For runtime correctness checks — that's
maf-fan-out-validator. This skill checks idiom and configuration, not topology correctness.
Anti-patterns covered
Each is a "rule" with a unique ID, a severity, and a deterministic search pattern. The MCP tool MafScanAntiPatterns ingests this list.
Security
MAF-AP-SEC-001 — DefaultAzureCredential in production code (severity: error)
Pattern: new DefaultAzureCredential() anywhere outside a test project (*Tests.csproj). Why: DefaultAzureCredential walks an authentication chain that includes developer credentials, environment variables, and managed identity. The chain order can change between SDK versions; production deployments should NEVER tolerate that surprise. Pin to the specific credential type your environment uses. Fix: Replace with ManagedIdentityCredential (Azure-hosted) or WorkloadIdentityCredential (Kubernetes), or ClientSecretCredential / ClientCertificateCredential for explicit service principals. Source: maf-constraints.instructions.md hard rule #4.
MAF-AP-SEC-002 — Hard-coded API keys (severity: error)
Pattern: String literal matching (sk-|api[-_]?key)[A-Za-z0-9_-]{16,} anywhere in .cs files. Why: Keys in source land in git history forever. Fix: Read from IConfiguration / Azure.Identity / Microsoft.Extensions.Configuration.UserSecrets.
MAF-AP-SEC-003 — EnableSensitiveData = true in non-dev (severity: error)
Pattern: EnableSensitiveData\s*=\s*true in a file that is not under tests/, not under samples/, and not inside an #if DEBUG block. Why: Sensitive-data logging in production leaks PII, prompts, and tool arguments to the log sink. Fix: Gate behind #if DEBUG or builder.Environment.IsDevelopment(). Source: maf-constraints.instructions.md hard rule #5.
Concurrency / state
MAF-AP-CONC-001 — Instance fields on AIContextProvider (severity: error)
Pattern: A class deriving from AIContextProvider (or ChatHistoryProvider) that declares any non-readonly instance field. Why: AIContextProvider instances are shared across sessions. Mutable instance state causes cross-session leakage, races, and non-deterministic responses. Fix: Use ProviderSessionState for per-session state, or make fields readonly and immutable. Source: maf-constraints.instructions.md hard rule #2.
MAF-AP-CONC-002 — .Result / .Wait() on async (severity: warning)
Pattern: \)\s*\.(?:Result|Wait)\b — a .Result / .Wait() immediately following a method CALL (e.g. SomeAsync().Result). Deliberately anchored on the call's close-paren rather than the bare member name: matching task.Result on any member would false-fire on the many non-Task .Result / .Wait properties in real code, so the bare-member form is intentionally out of scope (pinned by a regression test). Why: Sync-over-async deadlocks under SynchronizationContext. Agent runtimes pump async; mixing sync waits is a latent hang. Fix: await the expression. Make the calling method async.
Observability
MAF-AP-OBS-001 — Missing UseOpenTelemetry (severity: warning)
Pattern: A file constructs an AIAgentBuilder / ChatClientAgent but never calls UseOpenTelemetry(...) (anywhere in the same file or any sibling configuration file). Why: Without OTel, agent calls are invisible in production. Token usage, latency, errors all silent. Fix: Add .UseOpenTelemetry(otelOptions) to the builder chain. Wire to your existing OTel exporter. Source: Migration guide §13.
MAF-AP-OBS-002 — IChatClient instantiated without telemetry (severity: info)
Pattern: new ChatClient( or new OpenAIChatClient( not chained with .UseOpenTelemetry() before being passed to an agent builder. Why: OpenTelemetry must wrap the client to capture token costs. Wrap at the lowest level so every agent benefits.
Identity
MAF-AP-ID-001 — Missing ManagedIdentityCredential for Azure hosting (severity: info)
Pattern: A project references Microsoft.Extensions.Azure or Azure.AI.OpenAI and uses a secret-based credential (ClientSecretCredential, EnvironmentCredential) without a comment / config explaining why MSI was rejected. Why: Secret rotation is operational toil and a credential-leak risk. Azure-hosted services should default to managed identity. Fix: new ManagedIdentityCredential(clientId).
Output format
The scanner produces a markdown report:
## MAF anti-pattern scan —
### ❌ errors
| Rule | File | Line | Match |
| MAF-AP-SEC-001 | src/Auth.cs | 42 | new DefaultAzureCredential() |
...
### ⚠️ warnings
...
### ℹ️ info
...
### ✅ rules passed
How the MCP tool invokes this
The MafScanAntiPatterns(repoPath) tool walks all *.cs files under repoPath, applies the regex / Roslyn rules defined in this skill, and produces the report above. The rule IDs in this document are the source of truth; the tool's internal rule list mirrors them.
Updating this skill
When the team discovers a new anti-pattern that should be caught at scan time:
- Add a new
MAF-AP--entry above with rule + pattern + fix + source. - Add the matching rule constant in
src/maf-autopilot/Tools/AntiPatternScannerTool.cs. - Add a test in
src/maf-autopilot.Tests/AntiPatternScannerToolTests.csproving the new rule fires. - Cross-reference from
maf-constraints.instructions.mdif it represents a hard rule.
The cross-reference matters: if a constraint says "NEVER do X" but the scanner doesn't enforce it, the constraint is aspirational, not actionable.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: joslat
- Source: joslat/maf-doctor
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.