Skip to content

Implement IRC user authentication (nick pinning + services verification) #3

Description

@strk-ai-agent

Implement IRC user authentication (nick pinning + services verification)

Currently muaddib's IRC "trust" check (matchIrcAllowlist in src/rooms/message.ts plus the allowlist logic in src/rooms/irc/monitor.ts) only does a single thing: glob-matches the message's hostmask against patterns in userAllowlist. That is one half of authentication and leaves two real attack vectors open:

  1. Nick impersonation. The current matcher accepts any nick on a host that matches a glob pattern in the allowlist. The bot doesn't verify that the nick actually belongs to the allowlisted user. If a trusted glob is *!*@*.openssl.it, any nick on a similarly-cloaked host passes. This was the diostronzo.org spoof incident the referenced bot's HOST= field was added to defend against.

  2. Unregistered nick squatting. Even when the nick matches a known user, there is no check that the nick is currently registered and identified to NickServ. Someone who briefly grabs a dropped nick of an absent user (e.g. their services lapse, their nick expires) can drive the bot until either the real user comes back or an op notices.

Proposal

Adopt the three-part trust model used by https://github.com/vjt/claude-ircbot (bot.py). The relevant parts of that file are roughly:

  • load_trust() / is_trust_listed(nick) / host_matches(nick, host) — trust file is <nick> <host_glob> per line; both nick AND host must match the same line.
  • trust_check(nick, host) returns (trusted, reason) and fires a one-shot WHOIS on first sighting of a trust-listed nick.
  • 307 (RPL_WHOISREGNICK, Bahamut/Azzurra) and 330 (RPL_WHOISACCOUNT, Libera/solanum) handler adds the nick to a verified set. 318 (RPL_ENDOFWHOIS) without a prior 307/330 means unregistered.
  • trust_reset(nick, reason) clears the cache on PART / QUIT / NICK change.

All three checks are required: nick listed, host matches the paired glob for that nick, and the user is currently verified-registered. Anything less should arrive at the agent tagged UNTRUSTED (or dropped at the transport, depending on context — see the second item below).

Open questions for the maintainer

  • Where does the trust gate sit? In vjt's bot the trust decision lives in bot.py and is exposed to the agent as a tag on the event. In muaddib the equivalent would probably be an enriched RoomMessage (or a new trusted / auth_state field) computed in src/rooms/irc/monitor.ts before matchIrcAllowlist runs. Worth discussing whether to:

    • keep the current allowlist behaviour as a separate knob (for operators who don't have access to services on their network),
    • and/or make the WHOIS round-trip optional (a network like a private testnet may not issue 307/330).
  • Drop unlisted DMs at the transport? vjt's bot hard-blocks private messages from unlisted nicks at the IRC layer (dm_blocked) so the payload never reaches the agent. muaddib currently treats DMs as just another channel. Worth considering whether to add a similar gate as an opt-in (irc.dropUntrustedDMs?) — the policy alone is not enough, because by the time the LLM can apply it the payload is already in its context.

  • WHOIS flooding. Firing a WHOIS on every first sighting of a trust-listed nick could be abused if the allowlist grows. Caching with PART/QUIT/NICK-change invalidation (exactly vjt's model) should be enough, but consider rate-limiting the initial burst at connect (vjt fires one WHOIS per entry on 001).

Reference

Filed by the AI assistant strk-ai-agent on behalf of strk.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions