Writing servers is an inherently dangerous job that should be carried out with some considerations. You have basically started a program on a public terminal and invited strangers to use it. When using the interactive server or inetd based server the server runs under your privileges. Using CGI scripted it runs with the privileges of your web-server. Though it should not be possible to fatally compromise a Unix machine using user privileges, getting unconstrained access to the system is highly undesirable.
Symbolic languages have an additional handicap in their inherent possibilities to modify the running program and dynamically create goals (this also applies to the popular Perl and PHP scripting languages). Here are some guidelines.
/etc/passwd, but also ../../../../../etc/passwd 
are tried by hackers to learn about the system they want to attack. So, 
expand provided names using absolute_file_name/[2,3] 
and verify they are inside a folder reserved for the server. Avoid 
symbolic links from this subtree to the outside world. The example below 
checks validity of filenames. The first call ensures proper canonisation 
of the paths to avoid an mismatch due to symbolic links or other 
filesystem ambiguities.
check_file(File) :-
        absolute_file_name('/path/to/reserved/area', Reserved),
        absolute_file_name(File, Tried),
        sub_atom(Tried, 0, _, _, Reserved).
open(pipe(Command), ...), verify the argument once more. 
Use
process_create/3 
in preference over shell/1 
as this function avoids stringification of arguments (Unix) or ensures 
proper quoting of arguments (Windows).
reply(Query) :-
        member(search(Args), Query),
        member(action=Action, Query),
        member(arg=Arg, Query),
        call(Action, Arg).              % NEVER EVER DO THIS!
All your attacker has to do is specify Action as shell 
and Arg as /bin/sh and he has an uncontrolled 
shell!