Chapter 6

Security and Trust in Multi-Agent Systems

弘益人間 (홍익인간) · Benefit All Humanity

Trust is the foundation of cooperation. Just as human societies require trust to function effectively, multi-agent systems must establish security and trust mechanisms to protect all participants and enable safe collaboration for the collective good.

Security Challenges in Multi-Agent Systems

Multi-agent systems face unique security challenges due to their distributed nature, autonomous agents, and open environments.

Key Challenge: Balancing openness for collaboration with protection against malicious agents while maintaining system functionality and performance.

Primary security concerns:

Authentication and Identity Management

Agents must prove their identity before being trusted. Multiple authentication mechanisms exist:

class AgentAuthenticationSystem {
    constructor() {
        this.registeredAgents = new Map();
        this.sessions = new Map();
        this.crypto = require('crypto');
    }

    // Register new agent with public key
    registerAgent(agentId, publicKey, metadata) {
        if (this.registeredAgents.has(agentId)) {
            throw new Error('Agent already registered');
        }

        this.registeredAgents.set(agentId, {
            id: agentId,
            publicKey: publicKey,
            registeredAt: Date.now(),
            metadata: metadata,
            trustScore: 50, // Initial trust score
            verified: false
        });

        return { success: true, agentId: agentId };
    }

    // Authenticate agent with challenge-response
    async authenticate(agentId, signature, challenge) {
        const agent = this.registeredAgents.get(agentId);

        if (!agent) {
            throw new Error('Agent not registered');
        }

        // Verify signature
        const verify = this.crypto.createVerify('SHA256');
        verify.update(challenge);
        const isValid = verify.verify(agent.publicKey, signature, 'hex');

        if (!isValid) {
            this.recordFailedAuth(agentId);
            throw new Error('Authentication failed');
        }

        // Create session token
        const sessionToken = this.generateSessionToken();

        this.sessions.set(sessionToken, {
            agentId: agentId,
            createdAt: Date.now(),
            expiresAt: Date.now() + 3600000, // 1 hour
            permissions: this.getAgentPermissions(agentId)
        });

        return {
            success: true,
            sessionToken: sessionToken,
            expiresAt: this.sessions.get(sessionToken).expiresAt
        };
    }

    // Token-based authentication
    validateSession(sessionToken) {
        const session = this.sessions.get(sessionToken);

        if (!session) {
            throw new Error('Invalid session');
        }

        if (Date.now() > session.expiresAt) {
            this.sessions.delete(sessionToken);
            throw new Error('Session expired');
        }

        return session;
    }

    generateSessionToken() {
        return this.crypto.randomBytes(32).toString('hex');
    }

    recordFailedAuth(agentId) {
        const agent = this.registeredAgents.get(agentId);
        if (agent) {
            agent.failedAuthAttempts = (agent.failedAuthAttempts || 0) + 1;
            agent.trustScore = Math.max(0, agent.trustScore - 5);

            // Lock account after too many failures
            if (agent.failedAuthAttempts >= 5) {
                agent.locked = true;
            }
        }
    }

    getAgentPermissions(agentId) {
        const agent = this.registeredAgents.get(agentId);
        return {
            canSendMessages: agent.trustScore >= 30,
            canAccessResources: agent.verified && agent.trustScore >= 50,
            canCreateCoalitions: agent.verified && agent.trustScore >= 70,
            maxMessageRate: agent.trustScore >= 80 ? 1000 : 100
        };
    }
}

// 弘益人間: Secure authentication protecting all participants

Trust Models

Trust is fundamental to multi-agent collaboration. Trust models help agents evaluate the reliability of other agents.

Reputation-Based Trust

class ReputationSystem {
    constructor() {
        this.reputations = new Map();
        this.interactions = [];
        this.decayRate = 0.05;
    }

    // Record interaction outcome
    recordInteraction(agentA, agentB, outcome, context) {
        const interaction = {
            timestamp: Date.now(),
            initiator: agentA,
            respondent: agentB,
            outcome: outcome, // success, failure, partial
            rating: this.outcomeToRating(outcome),
            context: context
        };

        this.interactions.push(interaction);
        this.updateReputation(agentB, interaction);
    }

    outcomeToRating(outcome) {
        const ratings = {
            'success': 1.0,
            'partial': 0.5,
            'failure': 0.0,
            'malicious': -1.0
        };
        return ratings[outcome] || 0;
    }

    updateReputation(agentId, interaction) {
        const current = this.reputations.get(agentId) || {
            totalScore: 0,
            interactions: 0,
            reputation: 0.5
        };

        // Weighted average with recency bias
        const recencyWeight = 1.0;
        const newScore = current.totalScore * current.interactions +
                        interaction.rating * recencyWeight;
        const newCount = current.interactions + recencyWeight;

        current.totalScore = newScore;
        current.interactions = newCount;
        current.reputation = newScore / newCount;

        this.reputations.set(agentId, current);
    }

    getReputation(agentId) {
        const rep = this.reputations.get(agentId);
        return rep ? rep.reputation : 0.5; // Neutral for new agents
    }

    // Calculate trust based on reputation and context
    calculateTrust(agentId, context) {
        const baseRep = this.getReputation(agentId);

        // Context-specific reputation
        const contextRep = this.getContextualReputation(agentId, context);

        // Combine base and contextual reputation
        return baseRep * 0.6 + contextRep * 0.4;
    }

    getContextualReputation(agentId, context) {
        const relevant = this.interactions.filter(i =>
            i.respondent === agentId &&
            i.context === context
        );

        if (relevant.length === 0) {
            return this.getReputation(agentId);
        }

        const sum = relevant.reduce((s, i) => s + i.rating, 0);
        return sum / relevant.length;
    }

    // Decay old reputations over time
    decayReputations() {
        for (const [agentId, rep] of this.reputations) {
            // Pull toward neutral (0.5)
            rep.reputation += (0.5 - rep.reputation) * this.decayRate;
            this.reputations.set(agentId, rep);
        }
    }

    // Get most trusted agents
    getMostTrusted(count = 10) {
        return Array.from(this.reputations.entries())
            .sort((a, b) => b[1].reputation - a[1].reputation)
            .slice(0, count)
            .map(([id, rep]) => ({ agentId: id, reputation: rep.reputation }));
    }
}

// 弘익人間: Trust system ensuring reliable collaboration

Transitive Trust

Agents can leverage trust relationships transitively: if A trusts B, and B trusts C, then A may trust C to some degree.

class TransitiveTrustNetwork {
    constructor() {
        this.trustEdges = new Map(); // agentA -> { agentB: trust_value }
    }

    setDirectTrust(agentA, agentB, trustValue) {
        if (!this.trustEdges.has(agentA)) {
            this.trustEdges.set(agentA, new Map());
        }
        this.trustEdges.get(agentA).set(agentB, trustValue);
    }

    getDirectTrust(agentA, agentB) {
        const edges = this.trustEdges.get(agentA);
        return edges ? (edges.get(agentB) || 0) : 0;
    }

    // Calculate transitive trust through paths
    calculateTransitiveTrust(agentA, agentC, maxDepth = 3) {
        const paths = this.findPaths(agentA, agentC, maxDepth);

        if (paths.length === 0) {
            return 0; // No trust path
        }

        // Calculate trust for each path
        const pathTrusts = paths.map(path => this.pathTrust(path));

        // Return maximum trust path
        return Math.max(...pathTrusts);
    }

    pathTrust(path) {
        let trust = 1.0;

        for (let i = 0; i < path.length - 1; i++) {
            const edgeTrust = this.getDirectTrust(path[i], path[i + 1]);
            trust *= edgeTrust;
        }

        // Decay with path length
        const decay = Math.pow(0.8, path.length - 1);
        return trust * decay;
    }

    findPaths(start, end, maxDepth) {
        const paths = [];
        const visited = new Set();

        const dfs = (current, target, path, depth) => {
            if (current === target) {
                paths.push([...path]);
                return;
            }

            if (depth >= maxDepth) return;
            if (visited.has(current)) return;

            visited.add(current);

            const neighbors = this.trustEdges.get(current);
            if (neighbors) {
                for (const [neighbor, trust] of neighbors) {
                    if (trust > 0.3) { // Only follow strong trust edges
                        path.push(neighbor);
                        dfs(neighbor, target, path, depth + 1);
                        path.pop();
                    }
                }
            }

            visited.delete(current);
        };

        dfs(start, end, [start], 0);
        return paths;
    }
}

// 弘益人間: Building trust networks for community benefit

Secure Communication

Protecting message confidentiality and integrity is critical:

class SecureAgentCommunication {
    constructor(privateKey, publicKey) {
        this.privateKey = privateKey;
        this.publicKey = publicKey;
        this.crypto = require('crypto');
    }

    // Encrypt and sign message
    sendSecureMessage(recipientPublicKey, message) {
        // 1. Generate symmetric key for this message
        const symmetricKey = this.crypto.randomBytes(32);
        const iv = this.crypto.randomBytes(16);

        // 2. Encrypt message with symmetric key
        const cipher = this.crypto.createCipheriv('aes-256-gcm', symmetricKey, iv);
        let encrypted = cipher.update(JSON.stringify(message), 'utf8', 'hex');
        encrypted += cipher.final('hex');
        const authTag = cipher.getAuthTag();

        // 3. Encrypt symmetric key with recipient's public key
        const encryptedKey = this.crypto.publicEncrypt(
            recipientPublicKey,
            symmetricKey
        );

        // 4. Sign the package
        const sign = this.crypto.createSign('SHA256');
        sign.update(encrypted + iv.toString('hex') + authTag.toString('hex'));
        const signature = sign.sign(this.privateKey, 'hex');

        return {
            encryptedMessage: encrypted,
            encryptedKey: encryptedKey.toString('hex'),
            iv: iv.toString('hex'),
            authTag: authTag.toString('hex'),
            signature: signature,
            senderPublicKey: this.publicKey
        };
    }

    // Decrypt and verify message
    receiveSecureMessage(secureMessage) {
        // 1. Verify signature
        const verify = this.crypto.createVerify('SHA256');
        verify.update(
            secureMessage.encryptedMessage +
            secureMessage.iv +
            secureMessage.authTag
        );

        if (!verify.verify(secureMessage.senderPublicKey, secureMessage.signature, 'hex')) {
            throw new Error('Invalid signature');
        }

        // 2. Decrypt symmetric key
        const symmetricKey = this.crypto.privateDecrypt(
            this.privateKey,
            Buffer.from(secureMessage.encryptedKey, 'hex')
        );

        // 3. Decrypt message
        const decipher = this.crypto.createDecipheriv(
            'aes-256-gcm',
            symmetricKey,
            Buffer.from(secureMessage.iv, 'hex')
        );

        decipher.setAuthTag(Buffer.from(secureMessage.authTag, 'hex'));

        let decrypted = decipher.update(secureMessage.encryptedMessage, 'hex', 'utf8');
        decrypted += decipher.final('utf8');

        return JSON.parse(decrypted);
    }
}

// 弘益人間: Secure communication protecting all agents

Malicious Agent Detection

Systems must detect and isolate malicious agents:

class MaliciousAgentDetector {
    constructor() {
        this.behaviorProfiles = new Map();
        this.anomalyThreshold = 0.7;
        this.quarantined = new Set();
    }

    recordBehavior(agentId, behavior) {
        if (!this.behaviorProfiles.has(agentId)) {
            this.behaviorProfiles.set(agentId, {
                messageFrequency: [],
                failureRate: [],
                resourceUsage: [],
                interactionPatterns: []
            });
        }

        const profile = this.behaviorProfiles.get(agentId);
        profile.messageFrequency.push(behavior.messagesPerMinute || 0);
        profile.failureRate.push(behavior.failureRate || 0);
        profile.resourceUsage.push(behavior.resourceUsage || 0);

        // Keep only recent history
        const maxHistory = 100;
        Object.keys(profile).forEach(key => {
            if (profile[key].length > maxHistory) {
                profile[key].shift();
            }
        });

        // Check for anomalies
        const anomalyScore = this.detectAnomaly(agentId);
        if (anomalyScore > this.anomalyThreshold) {
            this.flagMalicious(agentId, anomalyScore);
        }
    }

    detectAnomaly(agentId) {
        const profile = this.behaviorProfiles.get(agentId);
        if (!profile) return 0;

        let anomalyScore = 0;

        // Check message frequency
        const avgFreq = this.average(profile.messageFrequency);
        const stdFreq = this.stdDev(profile.messageFrequency);
        const recentFreq = profile.messageFrequency.slice(-10);
        const recentAvg = this.average(recentFreq);

        if (recentAvg > avgFreq + 3 * stdFreq) {
            anomalyScore += 0.3; // Unusual message rate
        }

        // Check failure rate
        const recentFailures = this.average(profile.failureRate.slice(-10));
        if (recentFailures > 0.5) {
            anomalyScore += 0.3; // High failure rate
        }

        // Check resource usage
        const recentUsage = this.average(profile.resourceUsage.slice(-10));
        const avgUsage = this.average(profile.resourceUsage);
        if (recentUsage > avgUsage * 3) {
            anomalyScore += 0.4; // Excessive resource usage
        }

        return Math.min(1.0, anomalyScore);
    }

    flagMalicious(agentId, score) {
        console.warn(`Agent ${agentId} flagged as potentially malicious (score: ${score})`);

        this.quarantined.add(agentId);

        // Notify system administrators
        this.notifyAdministrators({
            agentId: agentId,
            reason: 'Anomalous behavior detected',
            anomalyScore: score,
            timestamp: Date.now()
        });
    }

    isQuarantined(agentId) {
        return this.quarantined.has(agentId);
    }

    average(arr) {
        return arr.length > 0 ? arr.reduce((sum, val) => sum + val, 0) / arr.length : 0;
    }

    stdDev(arr) {
        const avg = this.average(arr);
        const squareDiffs = arr.map(val => Math.pow(val - avg, 2));
        return Math.sqrt(this.average(squareDiffs));
    }
}

// 弘익人間: Protecting the community from malicious actors

Access Control

Fine-grained access control ensures agents can only access authorized resources:

class RoleBasedAccessControl {
    constructor() {
        this.roles = new Map();
        this.permissions = new Map();
        this.agentRoles = new Map();
    }

    defineRole(roleName, permissions) {
        this.roles.set(roleName, permissions);
    }

    assignRole(agentId, roleName) {
        if (!this.roles.has(roleName)) {
            throw new Error(`Role ${roleName} not defined`);
        }

        if (!this.agentRoles.has(agentId)) {
            this.agentRoles.set(agentId, new Set());
        }

        this.agentRoles.get(agentId).add(roleName);
    }

    hasPermission(agentId, permission) {
        const roles = this.agentRoles.get(agentId);
        if (!roles) return false;

        for (const roleName of roles) {
            const rolePerms = this.roles.get(roleName);
            if (rolePerms && rolePerms.includes(permission)) {
                return true;
            }
        }

        return false;
    }

    checkAccess(agentId, resource, action) {
        const permission = `${resource}:${action}`;

        if (!this.hasPermission(agentId, permission)) {
            throw new Error(`Access denied: ${agentId} cannot ${action} ${resource}`);
        }

        return true;
    }
}

// Example usage
const rbac = new RoleBasedAccessControl();

// Define roles
rbac.defineRole('admin', ['*:*']); // All permissions
rbac.defineRole('worker', ['tasks:read', 'tasks:execute', 'messages:send']);
rbac.defineRole('observer', ['tasks:read', 'messages:read']);

// Assign roles
rbac.assignRole('agent-001', 'admin');
rbac.assignRole('agent-002', 'worker');
rbac.assignRole('agent-003', 'observer');

// Check access
rbac.checkAccess('agent-002', 'tasks', 'execute'); // OK
// rbac.checkAccess('agent-003', 'tasks', 'execute'); // Error

// 弘익人間: Fair access control protecting shared resources

Chapter Summary

Review Questions

  1. What are the primary security concerns in multi-agent systems?
  2. How does challenge-response authentication work?
  3. Explain reputation-based trust and its advantages.
  4. What is transitive trust and how is it calculated?
  5. Describe the process of encrypting and signing a secure message.
  6. What behavioral patterns might indicate a malicious agent?
  7. How does role-based access control work?
  8. Why is reputation decay important in trust systems?
  9. What are the trade-offs between security and system openness?
  10. How do security mechanisms support the 弘익인간 principle?