Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
bagelhole avatar

Saas Security Posture

  • 72 installs
  • 44 repo stars
  • Updated May 22, 2026
  • bagelhole/devops-security-agent-skills

SaaS Security Posture is a Claude Code skill that audits and hardens a company's SaaS stack by enforcing SSO, MFA, OAuth governance, and admin-account controls across GitHub, Slack, Google Workspace, and AWS.

About

This skill audits and hardens a company's SaaS tool stack. A developer or IT lead uses it to enforce SSO and MFA, review OAuth grants, manage shadow IT, and secure admin accounts across Slack, GitHub, Google Workspace, and AWS. It supports SOC 2 preparation and post-incident hardening with command-driven checks.

  • Audits SaaS inventory and OAuth grants across GitHub, Slack, Google Workspace, AWS
  • Enforces SSO, MFA/2FA, IP allow-lists, and branch protection
  • SOC 2 evidence, shadow-IT discovery, and post-incident hardening

Saas Security Posture by the numbers

  • 72 all-time installs (skills.sh)
  • Ranked #1,165 of 2,203 Security skills by installs in the Skillselion catalog
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

saas-security-posture capabilities & compatibility

Free tooling but requires admin API tokens (e.g. SLACK_ADMIN_TOKEN) and admin access to each SaaS tool.

Capabilities
security audit
Works with
github · slack · aws · google drive
Use cases
security audit
Pricing
Free
From the docs

What saas-security-posture says it does

Secure every SaaS tool your company relies on with practical, command-driven hardening.
SKILL.md
Enforce 2FA and find non-compliant members
SKILL.md
npx skills add https://github.com/bagelhole/devops-security-agent-skills --skill saas-security-posture

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs72
repo stars44
Last updatedMay 22, 2026
Repositorybagelhole/devops-security-agent-skills

What it does

Audit and harden SaaS security posture across GitHub, Slack, Google Workspace, and AWS with SSO, MFA, and OAuth governance.

Who is it for?

Startups tightening SaaS security posture for SOC 2 or after an incident.

Skip if: Hardening application source code or infrastructure-as-code.

When should I use this skill?

You need to audit OAuth grants, enforce MFA/SSO, or secure admin accounts across SaaS tools.

What you get

SaaS tools have enforced SSO, MFA, OAuth governance, and hardened admin accounts.

  • SaaS inventory audit
  • Hardened SSO/MFA and OAuth settings
  • Master inventory template

By the numbers

  • Google Workspace password_length hardened to 14
  • Slack session forced to re-auth every 24 hours (86400s)

Files

SKILL.mdMarkdownGitHub ↗

SaaS Security Posture Management for Startups

Secure every SaaS tool your company relies on with practical, command-driven hardening.

1. When to Use This Skill

  • SOC 2 preparation — auditors need evidence of MFA, access controls, and OAuth governance.
  • Suspicious OAuth app — an employee authorized a third-party app with broad scopes.
  • SaaS sprawl — teams sign up for tools with company email and nobody tracks them.
  • Post-incident hardening — after phishing or credential leaks, tighten every surface.

2. SaaS Inventory Audit

Google Workspace — OAuth Grants

gam all users show tokens > oauth_tokens_audit.csv

GitHub — Installed Apps

gh api /orgs/{ORG}/installations --paginate \
  --jq '.installations[] | {app: .app_slug, permissions: .permissions, created: .created_at}'
gh api /orgs/{ORG}/credential-authorizations --paginate \
  --jq '.[] | {login: .login, credential_type: .credential_type}'

Slack — Approved and Pending Apps

curl -s -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  "https://slack.com/api/admin.apps.approved.list" | jq '.approved_apps[] | {name: .app.name, id: .app.id}'
curl -s -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  "https://slack.com/api/admin.apps.requests.list" | jq '.app_requests[]'

AWS — IAM Credential Report

aws iam generate-credential-report
aws iam get-credential-report --output text --query 'Content' | base64 -d > iam_credential_report.csv

Master Inventory Template

tools:
  - name: Google Workspace
    owner: it@company.com
    sso: true
    mfa: enforced
  - name: GitHub Enterprise
    owner: engineering@company.com
    sso: true
    mfa: enforced
  - name: Slack Business+
    owner: it@company.com
    sso: true
    app_approval: required
  - name: AWS Organizations
    owner: platform@company.com
    sso: true
    scp_enforced: true

---

3. GitHub Security Hardening

# Enforce 2FA and find non-compliant members
gh api -X PATCH /orgs/{ORG} -f two_factor_requirement_enabled=true
gh api /orgs/{ORG}/members?filter=2fa_disabled --paginate --jq '.[].login'

# Verify SAML SSO identities
gh api /orgs/{ORG}/credential-authorizations --paginate \
  --jq '.[] | {login: .login, saml_name_id: .saml_name_id}'

# Add IP allow list entry
gh api -X POST /orgs/{ORG}/ip-allow-list \
  -f allow_list_value="203.0.113.0/24" -f name="Office VPN" -F is_active=true

# Branch protection on main
gh api -X PUT /repos/{ORG}/{REPO}/branches/main/protection \
  -H "Accept: application/vnd.github+json" --input - <<'EOF'
{
  "required_status_checks": {"strict": true, "contexts": ["ci/build","ci/test"]},
  "enforce_admins": true,
  "required_pull_request_reviews": {
    "required_approving_review_count": 2,
    "dismiss_stale_reviews": true,
    "require_code_owner_reviews": true
  },
  "restrictions": null,
  "allow_force_pushes": false,
  "allow_deletions": false
}
EOF

# Audit PATs and revoke stale tokens
gh api /orgs/{ORG}/personal-access-tokens --paginate \
  --jq '.[] | {owner: .owner.login, name: .token_name, expires: .token_expires_at}'
gh api -X DELETE /orgs/{ORG}/personal-access-tokens/{PAT_ID}

# Audit deploy keys and webhooks
for repo in $(gh repo list {ORG} --limit 500 --json name -q '.[].name'); do
  gh api /repos/{ORG}/${repo}/keys --jq '.[] | {title: .title, read_only: .read_only}'
done
gh api /orgs/{ORG}/hooks --jq '.[] | {url: .config.url, events: .events, active: .active}'

---

4. Slack Security

# Require app approval
curl -s -X POST -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://slack.com/api/admin.apps.config.set" -d '{"app_approval_enabled": true}'

# Set workspace to invite-only
curl -s -X POST -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://slack.com/api/admin.teams.settings.setDiscoverability" \
  -d '{"team_id": "T0XXXXXXX", "discoverability": "invite_only"}'

# Force re-authentication every 24 hours
curl -s -X POST -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://slack.com/api/admin.teams.settings.setSessionDuration" \
  -d '{"team_id": "T0XXXXXXX", "session_duration": 86400}'

# Set message retention to 1 year
curl -s -X POST -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://slack.com/api/admin.teams.settings.setRetentionPolicy" \
  -d '{"team_id": "T0XXXXXXX", "retention_type": "all", "retention_duration": 365}'

# Audit Slack Connect shared channels
curl -s -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  "https://slack.com/api/admin.conversations.search?search_channel_types=connect" \
  | jq '.conversations[] | {name: .name, is_ext_shared: .is_ext_shared}'

---

5. Google Workspace Hardening

# Enforce 2-Step Verification and strong passwords
gam update org "/" settings 2sv enforced
gam update org "/" settings password_length 14

# Block all third-party OAuth apps, then whitelist specific ones
gam update org "/" settings oauth_access block_all
gam update org "/" settings oauth_access whitelist client_id:APP_CLIENT_ID_1

# Disable external Drive sharing and file transfers
gam update org "/" settings drive sharing_outside_domain off
gam update org "/" settings drive transfer_to_personal off
gam update org "/" settings groups external_members off

# Verify email authentication records
dig TXT company.com | grep "v=spf1"
dig TXT google._domainkey.company.com
dig TXT _dmarc.company.com
# Expected: v=DMARC1; p=reject; rua=mailto:dmarc-reports@company.com; pct=100

# Mobile device management
gam update org "/" settings mobile management advanced
gam update org "/" settings mobile screen_lock required
gam update org "/" settings mobile encryption required
gam update mobile ${DEVICE_ID} action wipe   # compromised device

---

6. AWS Account Security

# Root account lockdown — verify MFA, remove access keys
aws iam get-account-summary --query 'SummaryMap.AccountMFAEnabled'
aws iam get-account-summary --query 'SummaryMap.AccountAccessKeysPresent'

# SSO permission set with least privilege
aws sso-admin create-permission-set --instance-arn "${SSO_INSTANCE_ARN}" \
  --name "DeveloperAccess" --session-duration "PT8H"
aws sso-admin attach-managed-policy-to-permission-set \
  --instance-arn "${SSO_INSTANCE_ARN}" --permission-set-arn "${PERMISSION_SET_ARN}" \
  --managed-policy-arn "arn:aws:iam::aws:policy/ReadOnlyAccess"

Service Control Policies

{
  "Version": "2012-10-17",
  "Statement": [
    {"Sid": "DenyRootActions", "Effect": "Deny", "Action": "*", "Resource": "*",
     "Condition": {"StringLike": {"aws:PrincipalArn": "arn:aws:iam::*:root"}}},
    {"Sid": "DenyLeaveOrg", "Effect": "Deny",
     "Action": "organizations:LeaveOrganization", "Resource": "*"}
  ]
}
aws organizations create-policy --name "DenyRootActions" \
  --type SERVICE_CONTROL_POLICY --content file://deny-root-actions.json
aws organizations attach-policy --policy-id "${POLICY_ID}" --target-id "${ORG_ROOT_ID}"

# Organization-wide CloudTrail
aws cloudtrail create-trail --name org-security-trail \
  --s3-bucket-name company-cloudtrail-logs \
  --is-multi-region-trail --is-organization-trail --enable-log-file-validation
aws cloudtrail start-logging --name org-security-trail

---

7. OAuth App Review

Identify High-Risk Grants

# Google — find apps with dangerous scopes
gam all users show tokens | grep -E "(drive|gmail|admin)" > high_risk_oauth.txt

# GitHub — find apps with write access
gh api /orgs/{ORG}/installations --paginate \
  --jq '.installations[] | select(.permissions.contents == "write") | {app: .app_slug}'

Revoke Dangerous Grants

gam user compromised@company.com delete token clientid APP_CLIENT_ID  # single app
gam user compromised@company.com delete tokens                        # all apps
gh api -X DELETE /orgs/{ORG}/installations/{INSTALLATION_ID}           # GitHub app
curl -s -X POST -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://slack.com/api/admin.apps.uninstall" -d '{"app_id": "A0XXXXXXX"}'

Scope Risk Classification

CRITICAL — revoke unless justified:
  Google: mail.google.com, admin.directory.user | GitHub: admin:org, repo | Slack: admin
HIGH — review carefully:
  Google: googleapis.com/auth/drive | GitHub: contents:write | Slack: channels:read
LOW — generally safe:
  Google: userinfo.email | GitHub: read:org | Slack: identity.basic

---

8. Admin Account Protection

# Dedicated admin account in Google Workspace
gam create user admin-jdoe@company.com firstname "John (Admin)" lastname "Doe" \
  password "$(openssl rand -base64 32)" org "/Admins"
gam update user admin-jdoe@company.com admin on

# Require hardware security keys for the Admins OU
gam update org "/Admins" settings 2sv security_key_only

# AWS MFA enforcement policy
cat <<'EOF' > enforce-mfa-policy.json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyUnlessMFA", "Effect": "Deny",
    "NotAction": ["iam:CreateVirtualMFADevice","iam:EnableMFADevice",
                  "iam:GetUser","iam:ListMFADevices","sts:GetSessionToken"],
    "Resource": "*",
    "Condition": {"BoolIfExists": {"aws:MultiFactorAuthPresent": "false"}}
  }]
}
EOF
aws iam create-policy --policy-name EnforceMFA --policy-document file://enforce-mfa-policy.json

# Break-glass account for SSO outages
BREAK_GLASS_PW=$(openssl rand -base64 48)
gam create user breakglass@company.com firstname "Break" lastname "Glass" \
  password "${BREAK_GLASS_PW}" org "/Admins" admin on
# Store password in a sealed envelope in a physical safe
# After every use: rotate password, re-seal, log the incident

---

9. Data Loss Prevention

# Google Drive — block external sharing and restrict viewers
gam update org "/" settings drive sharing_outside_domain off
gam update org "/" settings drive disable_download_print_copy_for_viewers on

# GitHub — enable secret scanning and push protection org-wide
gh api -X PATCH /orgs/{ORG} -f security_product=secret_scanning -f enablement=enable_all
gh api -X PATCH /orgs/{ORG} -f security_product=secret_scanning_push_protection -f enablement=enable_all
gh api /orgs/{ORG}/secret-scanning/alerts --paginate \
  --jq '.[] | {repo: .repository.name, secret_type: .secret_type, state: .state}'

# Slack — restrict data export to org admins
curl -s -X POST -H "Authorization: Bearer ${SLACK_ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://slack.com/api/admin.teams.settings.setExportRestrictions" \
  -d '{"team_id": "T0XXXXXXX", "export_type": "org_admins_only"}'

# AWS — block all public S3 access at account level
aws s3control put-public-access-block --account-id "${AWS_ACCOUNT_ID}" \
  --public-access-block-configuration \
  "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

---

10. Shadow IT Detection

DNS-Based Discovery

SHADOW_IT_DOMAINS=("airtable.com" "notion.so" "trello.com" "asana.com"
  "monday.com" "clickup.com" "figma.com" "canva.com" "miro.com"
  "zapier.com" "dropbox.com" "box.com" "wetransfer.com")
for domain in "${SHADOW_IT_DOMAINS[@]}"; do
  count=$(grep -c "${domain}" /var/log/dns/query.log 2>/dev/null || echo "0")
  [ "${count}" -gt 0 ] && echo "DETECTED: ${domain} — ${count} queries"
done

Google Workspace Login Audit

gam report login parameters app_name \
  start_time "2026-03-01T00:00:00Z" end_time "2026-03-24T23:59:59Z" > login_audit.csv
gam report token > token_usage_report.csv

Proxy Log Analysis

awk '{print $7}' /var/log/squid/access.log | sed 's|https\?://||;s|/.*||' \
  | sort | uniq -c | sort -rn | head -50 > top_domains.txt
comm -23 <(awk '{print $2}' top_domains.txt | sort) \
  <(yq '.tools[].domains[]' saas-inventory.yaml | sort) > unapproved.txt

Automated Alerting

cat <<'SCRIPT' > /usr/local/bin/shadow-it-check.sh
#!/usr/bin/env bash
set -euo pipefail
APPROVED="/etc/security/approved-saas-domains.txt"
YESTERDAY=$(date -d "yesterday" +%d-%b-%Y)
grep "${YESTERDAY}" /var/log/dns/query.log | awk '{print $4}' | sort -u > /tmp/today.txt
NEW=$(comm -23 /tmp/today.txt <(sort "${APPROVED}"))
[ -n "${NEW}" ] && mail -s "[ALERT] Shadow IT" security@company.com <<< "${NEW}"
SCRIPT
chmod +x /usr/local/bin/shadow-it-check.sh
echo "0 8 * * * root /usr/local/bin/shadow-it-check.sh" >> /etc/cron.d/shadow-it-check

---

Quick Reference — Top 10 Priority Actions

#ActionScope
1Enforce MFA/2FA everywhereGoogle, GitHub, AWS, Slack
2Enable SSO with your IdPAll tools
3Audit and revoke OAuth grantsGoogle, GitHub
4Require Slack app approvalSlack
5Branch protection on mainGitHub
6Secret scanning + push protectionGitHub
7Block public S3 bucketsAWS
8Enable org-wide CloudTrailAWS
9Disable external Drive sharingGoogle
10Create break-glass admin accountsGoogle, AWS

Maintenance Cadence

Weekly: Review OAuth grants, secret scanning alerts, Slack app queue. Monthly: AWS IAM report, rotate service keys, admin account review, shadow IT scan. Quarterly: Full SaaS inventory refresh, OAuth pruning, break-glass test, SCP updates.

Related skills

FAQ

Which SaaS tools does it cover?

GitHub, Slack, Google Workspace, and AWS, with command-driven audits and hardening for each.

Does it help with SOC 2?

Yes, it produces evidence of MFA, access controls, and OAuth governance that auditors require.

Securityauditcompliancesecrets

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.