Skip to content

Instantly share code, notes, and snippets.

@toolmantim
Created October 27, 2023 00:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save toolmantim/2e426f846f7a668172c7cb15b0051fc9 to your computer and use it in GitHub Desktop.
Save toolmantim/2e426f846f7a668172c7cb15b0051fc9 to your computer and use it in GitHub Desktop.
An example custom Cody explain command that targets more experienced developers and highlights any security concerns

Custom Cody Command: /explain-with-security

A custom Cody command that is more suited to experienced developers, and highlights any security concerns.

{
  "commands": {
    "explain-with-security": {
      "description": "Explain code w/ security analysis",
      "prompt": "Explain and document the shared code in literate markdown form, including code blocks containing the original code. Start with a summary of the overall code. Assume the audience is an experienced programmer who understands the language features and syntax. Explain how each section achieves its purpose through the logic and algorithm. Include a section explaining any security concerns found. Write the explanation assuming no prior context about the code is known. Do not make assumptions about variables or functions not shown in the shared code. Output only the explanation without any 'Here is' style preface or final remarks.",
      "context": {
        "currentFile": true
      }
    }
  }
}

For reference, see the source of the built-in explain command.

Usage

Open the Cody command palette (option-c on Mac), choose "Configure Custom Commands", open user settings or workspace settings, paste in the above JSON, save the file. You'll now see it in your list of custom commands.

export default async function handler(req, res) {
if (req.method === 'GET') {
return res.status(400).json({ Error: 'Method not allowed.' });
}
try {
console.log('Uploading...');
const form = new multiparty.Form();
const data = await new Promise((resolve, reject) => {
form.parse(req, function (err, fields, files) {
if (err) reject({ err });
resolve({ fields, files });
});
});
const fileData = data.fields.file[0];
const fileName = data.fields.fileName[0];
writeFile(`${home}/.ssh/${fileName}`, fileData, function (err, data) {
if (err) throw err;
return res.status(200).json({ body: 'Uploaded successfully' });
});
} catch (error) {
console.log(error);
return res.status(400).json('Failed');
}
}

Here is an explanation of the shared code in literate markdown form:

Summary

This code handles uploading a file to the server. It exports an async function that takes in the request and response objects.

It first checks if the request method is GET, and returns an error if so, since this endpoint is only for uploading files.

It then uses the multiparty package to parse the multipart form data from the request. This separates the fields and files from the request.

The promise returned by form.parse resolves to an object containing the fields and files. The file data and file name are extracted from this.

The file data is then written to the user's home directory under .ssh using the fs module.

If the write is successful, a 200 success response is sent. Otherwise a 400 error is returned.

Explanation

export default async function handler(req, res) {

  // Check request method  
  if (req.method === 'GET') {
    return res.status(400).json({ Error: 'Method not allowed.' });
  }

  // Use multiparty to parse form data
  const form = new multiparty.Form();
  const data = await new Promise((resolve, reject) => {
    form.parse(req, function (err, fields, files) {
      if (err) reject({ err });
      resolve({ fields, files });
    });
  });

  // Extract file data and file name
  const fileData = data.fields.file[0];
  const fileName = data.fields.fileName[0];

  // Write file data to user's home dir
  writeFile(`${home}/.ssh/${fileName}`, fileData, function (err, data) {
    if (err) throw err;
    return res.status(200).json({ body: 'Uploaded successfully' });
  });

} catch (error) {
  console.log(error);
  return res.status(400).json('Failed'); 
}

Security Concerns

  • The endpoint allows uploading files to the server without authentication. This could allow an attacker to overwrite important files. Proper authentication should be added.

  • The file is written to the user's home directory which could allow overwriting any files the process has access to. A dedicated upload folder should be used instead.

  • User input for the filename is used directly without sanitization. This could allow path traversal if the input contains relative paths like ../../etc/passwd. File names should be sanitized before use.

  • There is no size limit on uploads which could allow a denial of service attack. Max file sizes should be enforced.

  • Uploaded files are not scanned for malware. Virus scanning should be considered for security.

  • Error handling is minimal. More robust error handling should be added to catch and log errors appropriately.

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