From lucidchart-pack
Security Basics for Lucidchart. Trigger: "lucidchart security basics".
npx claudepluginhub flight505/skill-forge --plugin lucidchart-packThis skill is limited to using the following tools:
Lucidchart documents often contain sensitive business diagrams — org charts, network topologies, database schemas, and architecture plans that reveal internal infrastructure. The API uses OAuth2 client credentials, meaning a compromised client secret grants access to every document the integration can reach. Collaboration sharing with granular permission levels (view, edit, owner) must be enfor...
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Analyzes multiple pages for keyword overlap, SEO cannibalization risks, and content duplication. Suggests differentiation, consolidation, and resolution strategies when reviewing similar content.
Share bugs, ideas, or general feedback.
Lucidchart documents often contain sensitive business diagrams — org charts, network topologies, database schemas, and architecture plans that reveal internal infrastructure. The API uses OAuth2 client credentials, meaning a compromised client secret grants access to every document the integration can reach. Collaboration sharing with granular permission levels (view, edit, owner) must be enforced server-side. API versioning via the Lucid-Api-Version header requires pinning to avoid unexpected schema changes that break validation logic.
Lucid-Api-Version header pinned to a tested version in all requests.env files in .gitignore — never committed to version control// OAuth2 client credentials — load from secrets manager at startup
const LUCID_CLIENT_ID = process.env.LUCID_CLIENT_ID;
const LUCID_CLIENT_SECRET = process.env.LUCID_CLIENT_SECRET;
function validateLucidConfig(): void {
if (!LUCID_CLIENT_ID || !LUCID_CLIENT_SECRET) {
throw new Error('Missing LUCID_CLIENT_ID or LUCID_CLIENT_SECRET');
}
}
async function getLucidAccessToken(): Promise<string> {
const resp = await fetch('https://api.lucid.co/oauth2/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: LUCID_CLIENT_ID!,
client_secret: LUCID_CLIENT_SECRET!,
}),
});
if (!resp.ok) throw new Error(`OAuth2 token request failed: ${resp.status}`);
const { access_token } = await resp.json();
return access_token;
// Cache token until expiry — never log it
}
import crypto from 'node:crypto';
const LUCID_WEBHOOK_SECRET = process.env.LUCID_WEBHOOK_SECRET!;
function verifyLucidWebhook(payload: string, signature: string): boolean {
const expected = crypto
.createHmac('sha256', LUCID_WEBHOOK_SECRET)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
app.post('/webhooks/lucidchart', (req, res) => {
const sig = req.headers['x-lucid-signature'] as string;
if (!sig || !verifyLucidWebhook(JSON.stringify(req.body), sig)) {
return res.status(401).json({ error: 'Invalid webhook signature' });
}
// Process verified document change event
});
// Validate document IDs and enforce API version pinning
const LUCID_API_VERSION = '1';
function validateDocumentId(docId: string): boolean {
// Lucid document IDs are alphanumeric UUIDs
return /^[a-f0-9-]{36}$/.test(docId);
}
function lucidApiHeaders(token: string): Record<string, string> {
return {
Authorization: `Bearer ${token}`,
'Lucid-Api-Version': LUCID_API_VERSION,
'Content-Type': 'application/json',
};
}
function redactDiagramMetadata(doc: Record<string, unknown>): Record<string, unknown> {
const sensitive = ['creator_email', 'collaborator_emails', 'share_link', 'embed_url'];
const redacted = { ...doc };
for (const field of sensitive) {
if (redacted[field]) redacted[field] = '[REDACTED]';
}
return redacted;
}
// Always redact before logging — diagrams may contain org charts and network layouts
type LucidPermission = 'view' | 'edit' | 'owner';
function assertDocumentPermission(
userRole: LucidPermission,
requiredRole: LucidPermission
): void {
const hierarchy: LucidPermission[] = ['view', 'edit', 'owner'];
if (hierarchy.indexOf(userRole) < hierarchy.indexOf(requiredRole)) {
throw new Error(`Insufficient permission: need "${requiredRole}", have "${userRole}"`);
}
}
// Enforce server-side — never rely on Lucidchart UI permissions alone
Lucid-Api-Version header pinned to a tested version| Vulnerability | Risk | Mitigation |
|---|---|---|
| Client secret in logs | Full API access compromise | Never log OAuth2 credentials; redact in error handlers |
| Unverified webhooks | Spoofed document change events | Reject requests without valid x-lucid-signature |
| Unpinned API version | Breaking schema changes bypass validation | Always send Lucid-Api-Version header |
| Over-permissioned sharing | Unauthorized diagram access | Enforce view/edit/owner hierarchy server-side |
| Diagram data in logs | Leaked org charts and network topology | Redact creator, collaborator, and share URLs |
See lucidchart-prod-checklist.