Loading...
Loading...
Use when auditing or hardening a Meteor 3 application. Triggers on missing check() on method arguments, missing this.userId guards on publications, browser-policy CSP, DDPRateLimiter rules, oauth-encryption via Accounts.config oauthSecretKey, audit-argument-checks, allow/deny legacy patterns, BrowserPolicy.content.disallowInlineScripts, BrowserPolicy.framing.disallow. Use this skill when the user asks about hardening, asks about a security review, or asks about CSP for a third-party script (Stripe, Google Maps, fonts).
npx skill4agent add meteor/agent-skills meteor-securitycheck()this.userIdMeteor.userId()this.userIdfieldsaudit-argument-checkscheck()browser-policyDDPRateLimiteroauthSecretKeyallowdenyimport { Meteor } from "meteor/meteor";
import { check, Match } from "meteor/check";
Meteor.methods({
async updateProfile(payload) {
check(payload, { displayName: String, bio: Match.Optional(String) });
if (!this.userId) {
throw new Meteor.Error("not-authorized");
}
await Meteor.users.updateAsync(this.userId, { $set: { profile: payload } });
},
async updateAddress(payload) {
check(payload, String);
if (!Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
await Meteor.users.updateAsync(Meteor.userId(), { $set: { address: payload } });
},
});checkMeteor.Error(code, reason)*AsyncMeteor.publish("items.mine", function () {
if (!this.userId) return this.ready();
return Items.find(
{ ownerId: this.userId },
{ fields: { title: 1, qty: 1 }, limit: 200 },
);
});browser-policymeteor add browser-policy// server top-level or inside Meteor.startup
import { BrowserPolicy } from "meteor/browser-policy-common";
import { Meteor } from "meteor/meteor";
Meteor.startup(async () => {
await BrowserPolicy.content.disallowInlineScripts();
BrowserPolicy.content.disallowEval();
BrowserPolicy.framing.disallow();
});BrowserPolicyreferences/browser-policy-csp.mdimport { DDPRateLimiter } from "meteor/ddp-rate-limiter";
DDPRateLimiter.addRule(
{
type: "method",
name: "login",
clientAddress: () => true,
},
5,
60000, // 5 attempts per 60s, per IP
);clientAddressconnectionIduserIdaccounts-baseAccounts.removeDefaultRateLimit()oauth-encryptionAccounts.configMeteor.startupmeteor node -e "console.log(require('crypto').randomBytes(16).toString('base64'))"import { Accounts } from "meteor/accounts-base";
Accounts.config({
oauthSecretKey: Meteor.settings.oauthSecretKey,
});accounts-oauthServiceConfiguration.configurations.secretservices.github.accessTokenaccessTokenSecretMeteor.users.services.<provider>.secretaudit-argument-checksmeteor add audit-argument-checkscheck()Meteor.methods({
rawLog(...args) {
check(args, [Match.Any]);
// ...
},
});Collection.allowCollection.denyMeteor.settings.public.<secret>publicsettings.jsonMeteor.usersfields: { username: 1, profile: 1 }BrowserPolicy.content.allowOriginForAllAccounts.config({ oauthSecretKey })Meteor.startupreferences/method-and-publish-guards.mdreferences/browser-policy-csp.mdreferences/eval-cases.mdmeteor-methodsmeteor-pubsubmeteor-accounts