0

tldr: is using a script spawned by my main process, which reads only a chunk of a sensitive file then passing the result to my main process - of any benefit?

in contrast to loading the file in my main process?

background:

I'm building my first CLI app as a personal project. The CLI app is supposed to be downloadable/installable by 3rd party users.

The app uses a Personal Access Token to authenticate the user with service A (which they already use) and perform some useful utilities.

  • The user is instructed to:
  • Log in to his account with service A.
  • Create a token (with the smallest amount of scope/least-priviledges) as possible..
  • Save the token in their netrc file.

This is an atrocious UX flow, but for starters it does the job.

The problem I have is that the .netrc file contains credentials for other services. I absolutely do not want to compromise those credentials for my users and bearing in mind I am a careless person that doesn't know any better sometimes, I have thought of the following process:

Rather than read the entire file in my own process:

  • Create a script that searches for a match in netrc.
  • The scripts takes only 1 parameter, an env. variable FILEPATH which points to the .netrc location. The matching keyword and the number of lines to match are not parameterised.
  • If a match is found, it reads the next 2 lines + the matching line.
  • Echoes it back to my process.

The purpose of this is simple (to me at least):

I don't want to load the entire netrc of the user in my own process.

Is this an entirely stupid idea? Semi-stupid?

Here's the scripts I'm using:

get-netrc-chunk.

  • greps for "api.foo.com". If found, fetch it, plus the next 2 lines.

  • reads env. var NRCPATH which points to the .netrc path.

  • unix-only for now.

#!/usr/bin/env bash

CLEAN_NRCPATH=${NRCPATH//[^/a-zA-Z0-9]/}

grep -A2 "api.foo.com" "$CLEAN_NRCPATH" | grep -v -- "^--$"

get-netrc-chunk.js.

executes the shell script: get-netrc-chunk via childProcess.execFile:

  • does not pass shell arguments
  • sets an env. var: NRCPATH pointing to the .netrc file path, which it calculates by joining homedir and ~/.netrc
import { join } from 'node:path'
import { promisify } from 'node:util'
import { execFile  as execFileAsync } from 'node:child_process'
import { chmod } from 'node:fs/promises'
import { homedir } from 'node:os'

const execFile = promisify(execFileAsync)

const grepChunkFromNetRC = async () => {
  // import the shell script file
  const netrcEntry = join(import.meta.dirname, 'grep-netrc-chunk')
  // elevate permissions to "read & execute"
  await chmod(netrcEntry, 0o500)
  
  // execute the shell script
  const { stdout, stderr } = await execFile(netrcEntry, {
    windowsHide: true,
    maxBuffer: 256,
    env: Object.freeze({ NRCPATH: join(homedir(), '.netrc') })
  })
   
  // downgrade permissions
  await chmod(netrcEntry, 0o000)
  
  if (stderr.length)
    throw new Error(stderr)

  // split stdout by newline and return the first 3 lines
  // this is already done by the shell script, but since 
  // today is an all-you-can-eat paranoia buffet, do it here too.
  return Object.freeze(stdout.trim().split('\n').slice(0, 3)) 
}

export { grepChunkFromNetRC }
14
  • 4
    What is this supposed to protect against? Commented Oct 20, 2024 at 17:21
  • 2
    But why is that a problem? Commented Oct 20, 2024 at 17:23
  • 2
    Your process runs under the user uid, thus it can already read the sensitive file if exploited, even if it delegates that to an external script. Modularizing a process is a good approach to achieve separation of privileges and the least privilege principles, but in this case you are not really separating the two processes. Think about it: what can and cannot an attacker do with and without the external script? This is called Threat modelling and it is a key step in designing secure applications. Commented Oct 20, 2024 at 17:57
  • 1
    .netrc sounds like a single file/place to store lots of un-encrypted credentials. Does that sound like a "best-practice" to you? If you have to store credentials you should use some encryption where the key is derived partly by and/or tied to hardware/user. (such as DPAPI on Windows) That's only to protect against theft/leakage of the file. If someone can execute code on the machine and as that user, they could also decrypt those encrypted values. Commented Oct 22, 2024 at 20:56
  • 1
    "Does that sound like a "best-practice" to you?" Hi man, appreciate the answer. What sounds or not sounds to me is irrelevant. That file is used by the big dogs, It is the indicated file to do so, by convention, in about 3-4 well trusted guides i've seen. I'd like to stick by them. The explanation you're giving out is insufficient to circumvent this convention, to me at least. If they get attacked in general, it's on them, not me. For one, by convention that file might be more readily protected because of that same fact; your suggestion is security-by-obscurity, no? I'm a bit mehh. Commented Oct 25, 2024 at 17:01

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.