# User bans and suspensions are enforced

- **Pattern:** `ab-000704` (`community-moderation-safety.report-enforcement.user-bans`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000704
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000704)

## Why it matters

Without enforceable bans, repeat violators face no real consequence — they continue posting after receiving warnings, and the moderation system becomes a signal they can ignore. OWASP A01:2021 (Broken Access Control, CWE-285) applies when ban records exist in the database but the enforcement check is missing from content-creation and interaction endpoints. A ban table with no WHERE clause enforcement is a paper ban: the record exists, but the behavior continues. Communities with no ban enforcement experience higher recidivism from bad actors who quickly learn there is no real cost to violations.

## Severity rationale

High because without enforcement checks at content-creation endpoints, banned users can immediately resume posting, rendering all prior moderation actions ineffective.

## Remediation

Check ban status at the start of every content-creation and interaction handler. Invalidate sessions on ban to force immediate logout:

```javascript
async function assertNotBanned(userId) {
  const user = await db.users.findOneById(userId);
  if (!user.banned) return;
  // Auto-lift expired temporary bans
  if (user.bannedUntil && user.bannedUntil < new Date()) {
    await db.users.update(userId, { banned: false, bannedUntil: null });
    return;
  }
  throw Object.assign(new Error('Account is banned'), { status: 403 });
}

// Apply at every post/comment/message endpoint
app.post('/api/posts', authenticate, async (req, res) => {
  await assertNotBanned(req.user.id);
  // ... create post
});
```

Store bans with at minimum: `userId`, `reason`, `bannedAt`, `bannedBy`, and optional `bannedUntil` for temporary suspensions.

## Detection

- **ID:** `user-bans`
- **Severity:** `high`
- **What to look for:** Check if moderators can ban or suspend users. Look for a user ban/suspension table or feature. Verify that banned users cannot post, comment, or create new accounts (or face friction).
- **Pass criteria:** Moderators can ban/suspend users for policy violations through at least 1 explicit mechanism (admin UI, CLI, or API endpoint). Enumerate all content-creation and interaction endpoints and confirm each checks the ban status before allowing action. Banned users cannot post new content or interact with the platform. A ban record is maintained with at least 3 fields: user ID, reason, and timestamp.
- **Fail criteria:** No user ban mechanism exists, or banned users can still post by creating new accounts. A ban table with no enforcement check in the post-creation path does not count as pass.
- **Skip (N/A) when:** Never — enforcement against repeat violators is essential.
- **Detail on fail:** `"No ban mechanism exists. Abusive users cannot be removed from the platform."`
- **Remediation:** Implement user bans that prevent banned users from posting or interacting:

  ```javascript
  // Moderator endpoint to ban user
  app.patch('/api/admin/users/:id/ban', verifyModerator, async (req, res) => {
    const { reason, duration } = req.body;

    // Calculate ban expiration (null = permanent)
    const bannedUntil = duration ? new Date(Date.now() + duration) : null;

    // Update user record
    await db.users.updateOne(
      { _id: req.params.id },
      {
        banned: true,
        bannedReason: reason,
        bannedUntil,
        bannedAt: new Date(),
        bannedBy: req.user.id
      }
    );

    // Invalidate all active sessions to force logout
    await db.sessions.deleteMany({ userId: req.params.id });

    res.status(200).json({ success: true, message: 'User banned' });
  });

  // Check ban status before all actions
  async function checkUserBan(userId) {
    const user = await db.users.findOne({ _id: userId });

    if (user.banned) {
      // Check if ban is temporary and expired
      if (user.bannedUntil && user.bannedUntil < new Date()) {
        // Unban user automatically
        await db.users.updateOne(
          { _id: userId },
          { banned: false, bannedUntil: null }
        );
      } else {
        throw new Error('User is banned');
      }
    }
  }

  // Middleware to enforce ban check on posting
  app.post('/api/posts', authenticate, async (req, res) => {
    try {
      await checkUserBan(req.user.id);
    } catch (err) {
      return res.status(403).json({ error: err.message });
    }

    // ... create post
  });
  ```

## External references

- cwe CWE-285
- owasp A01

Taxons: access-control

HTML version: https://auditbuffet.com/patterns/ab-000704
